<?php

namespace App\Http\Controllers;

use App\Models\Job;
use App\Models\Lead;
use App\Models\Contact;
use App\Models\User;
use App\Models\ActivityLog;
use Illuminate\Http\Request;
use Carbon\Carbon;

class JobController extends Controller
{
    public function index(Request $request)
    {
        $user    = auth()->user();
        $isTrades = $user->role?->name === 'trades';

        if ($isTrades) {
            // Trades users see only their assigned jobs that are not yet completed
            $query = $user->assignedJobs()
                ->with(['contact', 'consultant', 'manager'])
                ->where('status', '!=', 'completed');

            if ($request->stage && $request->stage !== 'all') {
                $query->where('stage', $request->stage);
            }
            if ($request->search) {
                $query->where(function ($q) use ($request) {
                    $q->where('job_number', 'like', '%'.$request->search.'%')
                      ->orWhereHas('contact', fn($c) => $c->where('first_name', 'like', '%'.$request->search.'%')
                        ->orWhere('last_name', 'like', '%'.$request->search.'%'));
                });
            }

            $jobs  = $query->orderByDesc('created_at')->paginate(20)->withQueryString();
            $stats = [
                'all'       => $user->assignedJobs()->count(),
                'active'    => $user->assignedJobs()->where('status', 'active')->count(),
                'on_hold'   => $user->assignedJobs()->where('status', 'on_hold')->count(),
                'completed' => $user->assignedJobs()->where('status', 'completed')->count(),
                'overdue'   => $user->assignedJobs()
                    ->where('status', 'active')
                    ->whereNotNull('expected_completion')
                    ->where('expected_completion', '<', Carbon::today())
                    ->count(),
            ];

            return view('jobs.index', compact('jobs', 'stats'))->with('isTrades', true);
        }

        // ── Non-trades: standard full list ──────────────────────────────────
        $query = Job::with(['contact', 'consultant', 'manager']);

        if ($request->stage && $request->stage !== 'all') {
            $query->where('stage', $request->stage);
        }
        if ($request->status && $request->status !== 'all') {
            $query->where('status', $request->status);
        }
        if ($request->search) {
            $query->where(function ($q) use ($request) {
                $q->where('job_number', 'like', '%'.$request->search.'%')
                  ->orWhereHas('contact', fn($c) => $c->where('first_name', 'like', '%'.$request->search.'%')
                    ->orWhere('last_name', 'like', '%'.$request->search.'%'));
            });
        }

        $allowedSorts = ['job_number', 'job_value', 'created_at', 'expected_completion'];
        $sortBy  = in_array($request->sort_by, $allowedSorts, true) ? $request->sort_by : 'created_at';
        $sortDir = $request->sort_dir === 'asc' ? 'asc' : 'desc';
        $jobs = $query->orderBy($sortBy, $sortDir)->paginate(20)->withQueryString();

        $stats = [
            'all'       => Job::count(),
            'active'    => Job::where('status', 'active')->count(),
            'on_hold'   => Job::where('status', 'on_hold')->count(),
            'completed' => Job::where('status', 'completed')->count(),
            'overdue'   => Job::where('status', 'active')
                ->whereNotNull('expected_completion')
                ->where('expected_completion', '<', Carbon::today())->count(),
        ];

        $selectedJob = null;
        if ($request->selected) {
            $selectedJob = Job::with(['contact', 'consultant', 'manager'])->find($request->selected);
        }

        return view('jobs.index', compact('jobs', 'stats', 'selectedJob'));
    }

    public function create()
    {
        $leads      = Lead::with('contact')->get();
        $contacts   = Contact::orderBy('first_name')->get();
        $consultants = User::whereHas('role', fn($q) => $q->where('name', 'sales_consultant'))
            ->where('is_active', true)->orderBy('name')->get();
        $projectManagers = User::whereHas('role', fn($q) => $q->where('name', 'project_manager'))
            ->where('is_active', true)->orderBy('name')->get();
        $designers = User::whereHas('role', fn($q) => $q->where('name', 'designer'))
            ->where('is_active', true)->orderBy('name')->get();
        return view('jobs.create', compact('leads', 'contacts', 'consultants', 'projectManagers', 'designers'));
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'lead_id'            => 'nullable|exists:leads,id',
            'contact_id'         => 'required|exists:contacts,id',
            'consultant_id'      => 'nullable|exists:users,id',
            'manager_id'         => 'nullable|exists:users,id',
            'designer_id'        => 'nullable|exists:users,id',
            'stage'              => 'required|string',
            'status'             => 'required|string',
            'priority'           => 'required|string',
            'source'             => 'nullable|string',
            'project_type'       => 'nullable|string',
            'design_style'       => 'nullable|string',
            'num_rooms'          => 'nullable|integer',
            'budget'             => 'nullable|numeric',
            'job_value'          => 'nullable|numeric',
            'sale_date'          => 'nullable|date',
            'expected_completion'=> 'nullable|date',
            'site_address'       => 'nullable|string',
            'site_suburb'        => 'nullable|string',
            'site_state'         => 'nullable|string',
            'site_postcode'      => 'nullable|string',
            'description'        => 'nullable|string',
            'notes'              => 'nullable|string',
            'next_action'        => 'nullable|string',
        ]);

        $data['job_number'] = 'J-' . str_pad((Job::withTrashed()->max('id') ?? 0) + 1, 4, '0', STR_PAD_LEFT);
        $job = Job::create($data);

        return redirect()->route('jobs.index')->with('success', 'Job created successfully.');
    }

    public function show(Job $job)
    {
        $user     = auth()->user();
        $isTrades = $user->role?->name === 'trades';

        // Trades users can only view jobs assigned to them
        if ($isTrades && ! $user->assignedJobs()->where('crm_jobs.id', $job->id)->exists()) {
            abort(403, 'You are not assigned to this job.');
        }

        $job->load([
            'contact', 'consultant', 'manager', 'lead',
            'worksOrders.items', 'productionOrders',
            'timeEntries.user.role', 'timeEntries.taskType', 'timeEntries.invoice',
            'variants.respondedBy', 'variants.quote',
            'quotes', 'quote', 'contract', 'checkMeasure',
            'jobInvoices.creator',
            'tradeUsers',
        ]);

        // Load available trades users for the assignment panel (admin/PM only)
        $availableTradesUsers = [];
        if (in_array($user->role?->name, ['office_admin', 'project_manager'])) {
            $availableTradesUsers = User::whereHas('role', fn($q) => $q->where('name', 'trades'))
                ->where('is_active', true)
                ->orderBy('name')
                ->get();
        }

        if ($isTrades) {
            // Simplified view for trades: just job info, no financial data
            return view('jobs.show', compact('job', 'isTrades', 'availableTradesUsers'));
        }

        // ── Full cost breakdown for non-trades ────────────────────────────────
        $directRoles = ['processor', 'factory_employee', 'lead_installer'];

        $variantRevenue    = (float) $job->variants->where('status', 'accepted')->sum('price_adjustment');
        $invoiceDeductions = $job->jobInvoices->sum(fn($inv) => (float) ($inv->invoice_amount ?? 0));
        $revenue = max(0, (float) ($job->job_value ?? 0) + $variantRevenue - $invoiceDeductions);

        $materialCost = $job->productionOrders->sum(fn($po) => (float) ($po->cost ?? 0));

        $completedEntries = $job->timeEntries->where('status', 'completed');

        $labourCost = $completedEntries->sum(function ($entry) use ($directRoles) {
            $roleName = $entry->user?->role?->name ?? '';
            $rate     = (float) ($entry->user?->hourly_rate ?? 0);
            $hrs      = $entry->duration_minutes / 60;
            if (in_array($roleName, $directRoles)) {
                return round($hrs * $rate, 2);
            }
            if ($entry->invoice && in_array($entry->invoice->status, ['approved', 'paid'])) {
                return round($hrs * $rate, 2);
            }
            return 0;
        });

        $approvedEntries = $completedEntries->filter(function($e) use($directRoles) {
            $role = $e->user?->role?->name ?? '';
            if (in_array($role, $directRoles)) return true;
            return $e->invoice && in_array($e->invoice->status, ['approved', 'paid']);
        });

        $totalCost   = $materialCost + $labourCost;
        $grossProfit = $revenue - $totalCost;
        $grossMargin = $revenue > 0 ? round(($grossProfit / $revenue) * 100, 1) : 0;

        $labourByTask = $approvedEntries
            ->groupBy(fn($e) => $e->taskType?->name ?? 'General')
            ->map(function ($entries) {
                $minutes = $entries->sum('duration_minutes');
                $cost = $entries->sum(function ($e) {
                    return round(($e->duration_minutes / 60) * (float) ($e->user?->hourly_rate ?? 0), 2);
                });
                return ['hours' => round($minutes / 60, 2), 'cost' => $cost, 'count' => $entries->count()];
            });

        $allTimeEntries = $job->timeEntries->where('status', 'completed');

        return view('jobs.show', compact(
            'job', 'revenue', 'variantRevenue', 'materialCost', 'labourCost',
            'totalCost', 'grossProfit', 'grossMargin', 'labourByTask', 'allTimeEntries',
            'availableTradesUsers', 'isTrades'
        ));
    }

    public function edit(Job $job)
    {
        $contacts = Contact::orderBy('first_name')->get();
        $consultants = User::whereHas('role', fn($q) => $q->where('name', 'sales_consultant'))
            ->where('is_active', true)->orderBy('name')->get();
        $projectManagers = User::whereHas('role', fn($q) => $q->where('name', 'project_manager'))
            ->where('is_active', true)->orderBy('name')->get();
        $designers = User::whereHas('role', fn($q) => $q->where('name', 'designer'))
            ->where('is_active', true)->orderBy('name')->get();
        return view('jobs.edit', compact('job', 'contacts', 'consultants', 'projectManagers', 'designers'));
    }

    public function update(Request $request, Job $job)
    {
        $job->update($request->only([
            'stage', 'status', 'priority', 'job_value', 'deposit_amount',
            'deposit_paid', 'cm_paid', 'delivery_paid', 'final_paid',
            'expected_completion', 'notes', 'next_action', 'warranty_expiry',
            'consultant_id', 'manager_id', 'designer_id',
        ]));
        return redirect()->route('jobs.index')->with('success', 'Job updated.');
    }

    public function destroy(Job $job)
    {
        $job->delete();
        return redirect()->route('jobs.index')->with('success', 'Job deleted.');
    }

    public function advanceStage(Request $request, Job $job)
    {
        $stages = ['lead', 'consult', 'sold', 'contracts', 'cm', 'processing', 'delivery', 'installation', 'completion'];

        if ($request->filled('stage') && in_array($request->stage, $stages, true)) {
            $targetStage = $request->stage;
        } else {
            $current = array_search($job->stage, $stages);
            if ($current === false || $current >= count($stages) - 1) {
                return back()->with('error', 'Job is already at the final stage.');
            }
            $targetStage = $stages[$current + 1];
        }

        $previousStage = $job->stage;
        $job->update(['stage' => $targetStage]);

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'Job',
            'loggable_id'   => $job->id,
            'action'        => 'Stage Changed',
            'description'   => "Job {$job->job_number} moved from " . ucfirst($previousStage) . " to " . ucfirst($targetStage),
        ]);

        return back()->with('success', "Job moved to " . ucfirst($targetStage) . " stage.");
    }

    /**
     * Assign a trades user to this job (admin/PM only, enforced by route middleware).
     */
    public function assignTrade(Request $request, Job $job)
    {
        $data = $request->validate([
            'user_id' => 'required|exists:users,id',
        ]);

        $user = User::findOrFail($data['user_id']);
        if ($user->role?->name !== 'trades') {
            return back()->with('error', 'Only users with the Trades role can be assigned here.');
        }

        // Attach (ignore duplicate)
        $job->tradeUsers()->syncWithoutDetaching([$data['user_id']]);

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'Job',
            'loggable_id'   => $job->id,
            'action'        => 'Trade Assigned',
            'description'   => "Trades user {$user->name} assigned to job {$job->job_number}.",
        ]);

        return back()->with('success', "{$user->name} assigned to this job.");
    }

    /**
     * Remove a trades user assignment from this job (admin/PM only).
     */
    public function removeTradeAssignment(Job $job, User $user)
    {
        $job->tradeUsers()->detach($user->id);

        ActivityLog::create([
            'user_id'       => auth()->id(),
            'loggable_type' => 'Job',
            'loggable_id'   => $job->id,
            'action'        => 'Trade Removed',
            'description'   => "Trades user {$user->name} removed from job {$job->job_number}.",
        ]);

        return back()->with('success', "{$user->name} removed from this job.");
    }
}
