<?php

namespace App\Http\Controllers;

use App\Models\Client;
use App\Models\Lead;
use App\Models\Project;
use App\Models\User;
use App\Services\CodeGeneratorService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class LeadController extends Controller
{
    public function __construct(private CodeGeneratorService $codeGenerator) {}

    public function index(Request $request): Response
    {
        $this->authorize('viewAny', Lead::class);

        $leads = Lead::with(['assignedTo', 'client'])
            ->whereNull('deleted_at')
            ->get()
            ->groupBy('status');

        $users = User::where('is_active', true)->select('id', 'name')->get();

        return Inertia::render('CRM/Index', [
            'leads' => $leads,
            'users' => $users,
        ]);
    }

    public function dashboard(): Response
    {
        $this->authorize('viewAny', Lead::class);

        $now = now();
        $monthStart = $now->copy()->startOfMonth();

        $stats = [
            'total_active'      => Lead::whereNotIn('status', ['won', 'lost'])->count(),
            'new_this_month'    => Lead::where('created_at', '>=', $monthStart)->count(),
            'won_this_month'    => Lead::where('status', 'won')->where('converted_at', '>=', $monthStart)->count(),
            'pipeline_value'    => Lead::whereNotIn('status', ['won', 'lost'])->sum('estimated_value'),
            'overdue_followups' => Lead::whereNotNull('follow_up_at')
                ->where('follow_up_at', '<', $now)
                ->whereNotIn('status', ['won', 'lost'])
                ->count(),
        ];

        // Conversion rate: won / (won+lost) in last 90 days
        $wonCount  = Lead::where('status', 'won')->where('updated_at', '>=', $now->copy()->subDays(90))->count();
        $lostCount = Lead::where('status', 'lost')->where('updated_at', '>=', $now->copy()->subDays(90))->count();
        $stats['conversion_rate'] = ($wonCount + $lostCount) > 0
            ? round(($wonCount / ($wonCount + $lostCount)) * 100)
            : 0;

        // Pipeline by status
        $byStatus = Lead::select('status', DB::raw('count(*) as count'), DB::raw('sum(estimated_value) as value'))
            ->groupBy('status')
            ->get()
            ->map(fn($r) => ['status' => $r->status, 'count' => $r->count, 'value' => (float)$r->value]);

        // By source
        $bySource = Lead::select('source', DB::raw('count(*) as count'),
            DB::raw('sum(case when status="won" then 1 else 0 end) as won'))
            ->groupBy('source')
            ->orderByDesc('count')
            ->get()
            ->map(fn($r) => ['source' => $r->source, 'count' => $r->count, 'won' => (int)$r->won]);

        // Monthly trend last 6 months
        $monthly = collect();
        for ($i = 5; $i >= 0; $i--) {
            $m     = $now->copy()->subMonths($i);
            $start = $m->copy()->startOfMonth();
            $end   = $m->copy()->endOfMonth();
            $monthly->push([
                'month'   => $m->format('M Y'),
                'created' => Lead::whereBetween('created_at', [$start, $end])->count(),
                'won'     => Lead::where('status', 'won')->whereBetween('converted_at', [$start, $end])->count(),
            ]);
        }

        // Recent activities
        $recentActivities = \App\Models\LeadActivity::with('lead:id,name')
            ->orderByDesc('performed_at')
            ->limit(8)
            ->get();

        // Upcoming follow-ups (next 7 days + overdue)
        $upcomingFollowups = Lead::whereNotNull('follow_up_at')
            ->whereNotIn('status', ['won', 'lost'])
            ->where('follow_up_at', '<=', $now->copy()->addDays(7))
            ->orderBy('follow_up_at')
            ->limit(10)
            ->get(['id', 'name', 'phone', 'status', 'follow_up_at']);

        return Inertia::render('CRM/Dashboard', [
            'stats'              => $stats,
            'by_status'          => $byStatus,
            'by_source'          => $bySource,
            'monthly_trend'      => $monthly,
            'recent_activities'  => $recentActivities,
            'upcoming_followups' => $upcomingFollowups,
        ]);
    }

    public function list(Request $request): Response
    {
        $this->authorize('viewAny', Lead::class);

        $query = Lead::with(['assignedTo'])
            ->whereNull('deleted_at');

        if ($search = $request->get('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                  ->orWhere('phone', 'like', "%{$search}%")
                  ->orWhere('email', 'like', "%{$search}%");
            });
        }
        if ($status = $request->get('status')) {
            $query->where('status', $status);
        }
        if ($source = $request->get('source')) {
            $query->where('source', $source);
        }
        if ($assignedTo = $request->get('assigned_to')) {
            $query->where('assigned_to', $assignedTo);
        }

        $leads = $query->orderByDesc('created_at')->paginate(25)->withQueryString();
        $users = User::where('is_active', true)->select('id', 'name')->get();

        return Inertia::render('CRM/Leads/Index', [
            'leads'   => $leads,
            'users'   => $users,
            'filters' => $request->only('search', 'status', 'source', 'assigned_to'),
        ]);
    }

    public function reports(): Response
    {
        $this->authorize('viewAny', Lead::class);

        $now = now();

        // Summary
        $total = Lead::count();
        $won   = Lead::where('status', 'won')->count();
        $lost  = Lead::where('status', 'lost')->count();
        $summary = [
            'total'    => $total,
            'won'      => $won,
            'lost'     => $lost,
            'win_rate' => ($won + $lost) > 0 ? round(($won / ($won + $lost)) * 100) : 0,
        ];

        // Full funnel
        $funnel = Lead::select('status', DB::raw('count(*) as count'), DB::raw('sum(estimated_value) as value'))
            ->groupBy('status')
            ->get()
            ->map(fn($r) => ['status' => $r->status, 'count' => $r->count, 'value' => (float)$r->value]);

        // Sources
        $sources = Lead::select('source', DB::raw('count(*) as count'),
            DB::raw('sum(case when status="won" then 1 else 0 end) as won'))
            ->groupBy('source')
            ->orderByDesc('count')
            ->get()
            ->map(fn($r) => ['source' => $r->source, 'count' => (int)$r->count, 'won' => (int)$r->won]);

        // Lost reasons
        $lostReasons = Lead::where('status', 'lost')
            ->whereNotNull('lost_reason')
            ->select('lost_reason', DB::raw('count(*) as count'))
            ->groupBy('lost_reason')
            ->orderByDesc('count')
            ->limit(10)
            ->get()
            ->map(fn($r) => ['reason' => $r->lost_reason, 'count' => $r->count]);

        // Team performance
        $team = Lead::select('assigned_to', DB::raw('count(*) as assigned'),
            DB::raw('sum(case when status="won" then 1 else 0 end) as won'))
            ->whereNotNull('assigned_to')
            ->groupBy('assigned_to')
            ->with('assignedTo:id,name')
            ->get()
            ->map(fn($r) => [
                'user_id'  => $r->assigned_to,
                'name'     => $r->assignedTo?->name ?? 'Unknown',
                'assigned' => (int)$r->assigned,
                'won'      => (int)$r->won,
            ])
            ->sortByDesc('won')
            ->values();

        // Monthly last 12
        $monthly = collect();
        for ($i = 11; $i >= 0; $i--) {
            $m     = $now->copy()->subMonths($i);
            $start = $m->copy()->startOfMonth();
            $end   = $m->copy()->endOfMonth();
            $monthly->push([
                'month'   => $m->format('M Y'),
                'created' => Lead::whereBetween('created_at', [$start, $end])->count(),
                'won'     => Lead::where('status', 'won')->whereBetween('converted_at', [$start, $end])->count(),
                'lost'    => Lead::where('status', 'lost')->whereBetween('updated_at', [$start, $end])->count(),
            ]);
        }

        return Inertia::render('CRM/Reports', [
            'summary'      => $summary,
            'funnel'       => $funnel,
            'sources'      => $sources,
            'lost_reasons' => $lostReasons,
            'team'         => $team,
            'monthly'      => $monthly,
        ]);
    }

    public function followUps(Request $request): Response
    {
        $this->authorize('viewAny', Lead::class);

        $leads = Lead::with(['assignedTo'])
            ->whereNotNull('follow_up_at')
            ->whereNotIn('status', ['won', 'lost'])
            ->orderBy('follow_up_at')
            ->paginate(25);

        return Inertia::render('CRM/FollowUps', [
            'leads' => $leads,
        ]);
    }

    public function create(): Response
    {
        $this->authorize('create', Lead::class);

        return Inertia::render('CRM/Leads/Create', [
            'users' => User::where('is_active', true)->select('id', 'name')->get(),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $this->authorize('create', Lead::class);

        $validated = $request->validate([
            'name'            => 'required|string|max:150',
            'phone'           => 'required|string|max:20',
            'email'           => 'nullable|email|max:150',
            'source'          => 'required|in:referral,facebook,instagram,website,walk_in,cold_call,exhibition,other',
            'project_type'    => 'nullable|string|max:100',
            'estimated_value' => 'nullable|numeric|min:0',
            'assigned_to'     => 'nullable|uuid|exists:users,id',
            'follow_up_at'    => 'nullable|date',
            'notes'           => 'nullable|string',
        ]);

        $code = $this->codeGenerator->generate('LD', 'leads');
        Lead::create(array_merge($validated, [
            'code'       => $code,
            'created_by' => auth()->id(),
        ]));

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

    public function show(Lead $lead): Response
    {
        $this->authorize('view', $lead);

        $lead->load(['assignedTo', 'client', 'activities.performedBy', 'createdBy', 'project']);

        return Inertia::render('CRM/Leads/Show', [
            'lead'  => $lead,
            'users' => User::where('is_active', true)->select('id', 'name')->get(),
        ]);
    }

    public function edit(Lead $lead): Response
    {
        $this->authorize('update', $lead);

        return Inertia::render('CRM/Leads/Edit', [
            'lead'  => $lead,
            'users' => User::where('is_active', true)->select('id', 'name')->get(),
        ]);
    }

    public function update(Request $request, Lead $lead): RedirectResponse
    {
        $this->authorize('update', $lead);

        $validated = $request->validate([
            'name'            => 'required|string|max:150',
            'phone'           => 'required|string|max:20',
            'email'           => 'nullable|email|max:150',
            'source'          => 'required|in:referral,facebook,instagram,website,walk_in,cold_call,exhibition,other',
            'status'          => 'sometimes|in:new,contacted,qualified,proposal_sent,won,lost',
            'project_type'    => 'nullable|string|max:100',
            'estimated_value' => 'nullable|numeric|min:0',
            'assigned_to'     => 'nullable|uuid|exists:users,id',
            'follow_up_at'    => 'nullable|date',
            'notes'           => 'nullable|string',
        ]);

        $lead->update($validated);

        return redirect()->route('crm.leads.show', $lead)->with('success', 'Lead updated.');
    }

    public function destroy(Lead $lead): RedirectResponse
    {
        $this->authorize('delete', $lead);
        $lead->delete();
        return redirect()->route('crm.index')->with('success', 'Lead deleted.');
    }

    public function updateStatus(Request $request, Lead $lead): RedirectResponse
    {
        $this->authorize('update', $lead);

        $validated = $request->validate([
            'status'        => 'required|in:new,contacted,qualified,proposal_sent,won,lost',
            'lost_reason'   => 'required_if:status,lost|nullable|string',
            'create_project'=> 'nullable|boolean',
            'project_name'  => 'nullable|string|max:200',
        ]);

        DB::transaction(function () use ($validated, $lead) {
            $lead->update([
                'status'       => $validated['status'],
                'lost_reason'  => $validated['lost_reason'] ?? null,
                'converted_at' => $validated['status'] === 'won' ? now() : null,
            ]);

            if ($validated['status'] === 'won' && ($validated['create_project'] ?? false)) {
                $codeService = app(CodeGeneratorService::class);
                $code = $codeService->generate('PRJ', 'projects');

                $client = $lead->client;
                if (!$client) {
                    $clientCode = $codeService->generate('CL', 'clients');
                    $client = Client::create([
                        'code'       => $clientCode,
                        'name'       => $lead->name,
                        'phone'      => $lead->phone,
                        'email'      => $lead->email,
                        'type'       => 'individual',
                        'created_by' => auth()->id(),
                    ]);
                    $lead->update(['client_id' => $client->id]);
                }

                Project::create([
                    'code'         => $code,
                    'name'         => $validated['project_name'] ?? "Project for {$lead->name}",
                    'client_id'    => $client->id,
                    'lead_id'      => $lead->id,
                    'type'         => 'residential',
                    'status'       => 'survey',
                    'site_address' => '',
                    'created_by'   => auth()->id(),
                ]);
            }
        });

        return back()->with('success', 'Lead status updated.');
    }

    public function followUpDone(Request $request, Lead $lead): RedirectResponse
    {
        $this->authorize('update', $lead);
        $lead->update(['follow_up_at' => null]);
        return back()->with('success', 'Follow-up marked as done.');
    }

    public function convertToClient(Request $request, Lead $lead): RedirectResponse
    {
        $this->authorize('update', $lead);

        if ($lead->client_id) {
            return back()->with('error', 'Lead is already linked to a client.');
        }

        $codeService = app(CodeGeneratorService::class);
        $code = $codeService->generate('CL', 'clients');

        $client = Client::create([
            'code'       => $code,
            'name'       => $lead->name,
            'phone'      => $lead->phone,
            'email'      => $lead->email,
            'type'       => 'individual',
            'created_by' => auth()->id(),
        ]);

        $lead->update(['client_id' => $client->id]);

        return redirect()->route('clients.show', $client)->with('success', 'Lead converted to client.');
    }
}
