<?php

namespace App\Http\Controllers;

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

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

    public function index(Request $request): Response
    {
        $query = Quotation::with(['client', 'lead', 'project', 'createdBy'])
            ->whereNull('deleted_at');

        if ($search = $request->get('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('code', 'like', "%{$search}%")
                  ->orWhere('subject', 'like', "%{$search}%")
                  ->orWhereHas('client', fn($q) => $q->where('name', 'like', "%{$search}%"));
            });
        }
        if ($status = $request->get('status')) {
            $query->where('status', $status);
        }

        $quotations = $query->orderByDesc('created_at')->paginate(20)->withQueryString();

        return Inertia::render('Quotations/Index', [
            'quotations' => $quotations,
            'filters'    => $request->only('search', 'status'),
        ]);
    }

    public function create(Request $request): Response
    {
        return Inertia::render('Quotations/Create', [
            'clients'  => Client::orderBy('name')->get(['id', 'name', 'code', 'phone']),
            'leads'    => Lead::whereNotIn('status', ['won', 'lost'])->orderBy('name')->get(['id', 'name', 'phone', 'estimated_value']),
            'projects' => Project::whereNotIn('status', ['completed', 'cancelled'])->orderBy('name')->get(['id', 'name', 'code']),
            'prefill'  => [
                'lead_id'    => $request->get('lead_id'),
                'client_id'  => $request->get('client_id'),
                'project_id' => $request->get('project_id'),
            ],
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'client_id'       => 'nullable|uuid|exists:clients,id',
            'lead_id'         => 'nullable|uuid|exists:leads,id',
            'project_id'      => 'nullable|uuid|exists:projects,id',
            'subject'         => 'required|string|max:250',
            'valid_until'     => 'nullable|date',
            'discount_type'   => 'required|in:percentage,fixed',
            'discount_value'  => 'nullable|numeric|min:0',
            'vat_pct'         => 'nullable|numeric|min:0|max:100',
            'terms'           => 'nullable|string',
            'notes'           => 'nullable|string',
            'items'           => 'required|array|min:1',
            'items.*.category'    => 'required|string|max:100',
            'items.*.description' => 'required|string|max:250',
            'items.*.unit'        => 'required|string|max:30',
            'items.*.quantity'    => 'required|numeric|min:0.01',
            'items.*.unit_rate'   => 'required|numeric|min:0',
        ]);

        if (empty($validated['client_id']) && empty($validated['lead_id'])) {
            return back()->withErrors(['client_id' => 'Select a client or at least a lead.'])->withInput();
        }

        DB::transaction(function () use ($validated, $request) {
            $code = $this->codeGenerator->generate('QT', 'quotations');
            $totals = $this->calculateTotals($validated);

            $quotation = Quotation::create([
                'code'            => $code,
                'client_id'       => $validated['client_id'] ?? null,
                'lead_id'         => $validated['lead_id'] ?? null,
                'project_id'      => $validated['project_id'] ?? null,
                'subject'         => $validated['subject'],
                'valid_until'     => $validated['valid_until'] ?? null,
                'discount_type'   => $validated['discount_type'],
                'discount_value'  => $validated['discount_value'] ?? 0,
                'discount_amount' => $totals['discount_amount'],
                'vat_pct'         => $validated['vat_pct'] ?? 0,
                'subtotal'        => $totals['subtotal'],
                'vat_amount'      => $totals['vat_amount'],
                'grand_total'     => $totals['grand_total'],
                'terms'           => $validated['terms'] ?? null,
                'notes'           => $validated['notes'] ?? null,
                'created_by'      => auth()->id(),
            ]);

            foreach ($validated['items'] as $seq => $item) {
                $total = round($item['quantity'] * $item['unit_rate'], 2);
                QuotationItem::create([
                    'quotation_id' => $quotation->id,
                    'category'     => $item['category'],
                    'description'  => $item['description'],
                    'unit'         => $item['unit'],
                    'quantity'     => $item['quantity'],
                    'unit_rate'    => $item['unit_rate'],
                    'total'        => $total,
                    'sequence'     => $seq,
                ]);
            }
        });

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

    public function show(Quotation $quotation): Response
    {
        $quotation->load(['client', 'lead', 'project', 'items', 'createdBy']);

        return Inertia::render('Quotations/Show', [
            'quotation' => $quotation,
        ]);
    }

    public function edit(Quotation $quotation): Response
    {
        if (!in_array($quotation->status, ['draft', 'sent', 'under_review'])) {
            return redirect()->route('quotations.show', $quotation)
                ->with('error', 'Only draft or sent quotations can be edited.');
        }

        $quotation->load(['items']);

        return Inertia::render('Quotations/Edit', [
            'quotation' => $quotation,
            'clients'   => Client::orderBy('name')->get(['id', 'name', 'code', 'phone']),
            'leads'     => Lead::whereNotIn('status', ['won', 'lost'])->orderBy('name')->get(['id', 'name', 'phone']),
            'projects'  => Project::whereNotIn('status', ['completed', 'cancelled'])->orderBy('name')->get(['id', 'name', 'code']),
        ]);
    }

    public function update(Request $request, Quotation $quotation): RedirectResponse
    {
        $validated = $request->validate([
            'client_id'       => 'nullable|uuid|exists:clients,id',
            'lead_id'         => 'nullable|uuid|exists:leads,id',
            'project_id'      => 'nullable|uuid|exists:projects,id',
            'subject'         => 'required|string|max:250',
            'valid_until'     => 'nullable|date',
            'discount_type'   => 'required|in:percentage,fixed',
            'discount_value'  => 'nullable|numeric|min:0',
            'vat_pct'         => 'nullable|numeric|min:0|max:100',
            'terms'           => 'nullable|string',
            'notes'           => 'nullable|string',
            'items'           => 'required|array|min:1',
            'items.*.category'    => 'required|string|max:100',
            'items.*.description' => 'required|string|max:250',
            'items.*.unit'        => 'required|string|max:30',
            'items.*.quantity'    => 'required|numeric|min:0.01',
            'items.*.unit_rate'   => 'required|numeric|min:0',
        ]);

        DB::transaction(function () use ($validated, $quotation) {
            $totals = $this->calculateTotals($validated);

            $quotation->update([
                'client_id'       => $validated['client_id'],
                'lead_id'         => $validated['lead_id'] ?? null,
                'project_id'      => $validated['project_id'] ?? null,
                'subject'         => $validated['subject'],
                'valid_until'     => $validated['valid_until'] ?? null,
                'discount_type'   => $validated['discount_type'],
                'discount_value'  => $validated['discount_value'] ?? 0,
                'discount_amount' => $totals['discount_amount'],
                'vat_pct'         => $validated['vat_pct'] ?? 0,
                'subtotal'        => $totals['subtotal'],
                'vat_amount'      => $totals['vat_amount'],
                'grand_total'     => $totals['grand_total'],
                'terms'           => $validated['terms'] ?? null,
                'notes'           => $validated['notes'] ?? null,
            ]);

            // Replace items
            $quotation->items()->delete();
            foreach ($validated['items'] as $seq => $item) {
                QuotationItem::create([
                    'quotation_id' => $quotation->id,
                    'category'     => $item['category'],
                    'description'  => $item['description'],
                    'unit'         => $item['unit'],
                    'quantity'     => $item['quantity'],
                    'unit_rate'    => $item['unit_rate'],
                    'total'        => round($item['quantity'] * $item['unit_rate'], 2),
                    'sequence'     => $seq,
                ]);
            }
        });

        return redirect()->route('quotations.show', $quotation)->with('success', 'Quotation updated.');
    }

    public function destroy(Quotation $quotation): RedirectResponse
    {
        $quotation->delete();
        return redirect()->route('quotations.index')->with('success', 'Quotation deleted.');
    }

    /** Mark as Sent */
    public function markSent(Quotation $quotation): RedirectResponse
    {
        $quotation->update(['status' => 'sent']);
        return back()->with('success', 'Quotation marked as sent.');
    }

    /** Approve */
    public function approve(Quotation $quotation): RedirectResponse
    {
        $quotation->update(['status' => 'approved']);
        // Update linked lead estimated_value
        if ($quotation->lead_id) {
            $quotation->lead->update(['estimated_value' => $quotation->grand_total]);
        }
        return back()->with('success', 'Quotation approved.');
    }

    /** Reject */
    public function reject(Request $request, Quotation $quotation): RedirectResponse
    {
        $quotation->update(['status' => 'rejected']);
        if ($quotation->lead_id) {
            $quotation->lead->update(['status' => 'lost', 'lost_reason' => 'Quotation rejected']);
        }
        return back()->with('success', 'Quotation rejected.');
    }

    /** Convert approved quotation to a Project */
    public function convertToProject(Request $request, Quotation $quotation): RedirectResponse
    {
        if ($quotation->status !== 'approved') {
            return back()->with('error', 'Only approved quotations can be converted to a project.');
        }

        $request->validate(['project_name' => 'required|string|max:200']);

        DB::transaction(function () use ($request, $quotation) {
            $codeService = app(CodeGeneratorService::class);

            // Auto-create client from lead if quotation has no client yet
            $clientId = $quotation->client_id;
            if (!$clientId && $quotation->lead_id) {
                $lead = $quotation->lead;
                if ($lead->client_id) {
                    $clientId = $lead->client_id;
                } else {
                    $client = Client::create([
                        'code'       => $codeService->generate('CL', 'clients'),
                        'name'       => $lead->name,
                        'phone'      => $lead->phone,
                        'email'      => $lead->email,
                        'type'       => 'individual',
                        'created_by' => auth()->id(),
                    ]);
                    $clientId = $client->id;
                    $lead->update(['client_id' => $clientId]);
                }
                $quotation->update(['client_id' => $clientId]);
            }

            $project = Project::create([
                'code'           => $codeService->generate('PRJ', 'projects'),
                'name'           => $request->project_name,
                'client_id'      => $clientId,
                'lead_id'        => $quotation->lead_id,
                'type'           => 'residential',
                'status'         => 'planning',
                'site_address'   => '',
                'contract_value' => $quotation->grand_total,
                'created_by'     => auth()->id(),
            ]);

            $quotation->update(['status' => 'converted', 'project_id' => $project->id]);

            if ($quotation->lead_id) {
                $quotation->lead->update([
                    'status'       => 'won',
                    'converted_at' => now(),
                    'client_id'    => $clientId,
                ]);
            }
        });

        return redirect()->route('projects.show', $quotation->fresh()->project_id)
            ->with('success', 'Project created from quotation!');
    }

    private function calculateTotals(array $data): array
    {
        $subtotal = collect($data['items'])->sum(fn($i) => $i['quantity'] * $i['unit_rate']);
        $discountValue = $data['discount_value'] ?? 0;
        $discountAmount = $data['discount_type'] === 'percentage'
            ? round($subtotal * $discountValue / 100, 2)
            : min($discountValue, $subtotal);
        $afterDiscount = $subtotal - $discountAmount;
        $vatPct = $data['vat_pct'] ?? 0;
        $vatAmount = round($afterDiscount * $vatPct / 100, 2);
        $grandTotal = $afterDiscount + $vatAmount;

        return [
            'subtotal'        => round($subtotal, 2),
            'discount_amount' => $discountAmount,
            'vat_amount'      => $vatAmount,
            'grand_total'     => round($grandTotal, 2),
        ];
    }
}
