<?php
namespace App\Http\Controllers;
use App\Models as M;
use App\Services\ApprovalService;
use App\Services\GhanaTaxService;
use App\Services\SequenceService;
use App\Support\CrudRegistry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class QuotationController extends Controller {
    use Concerns\FxDoc;
    public function index(Request $r) { return app(CrudController::class)->index($r, 'quotations'); }
    public function show(int $id) { return app(CrudController::class)->show('quotations', $id); }
    public function create(Request $r) {
        $this->need('sales.create');
        return view('docs.quotation.form', $this->formData(new M\Quotation(['quotation_date' => date('Y-m-d'), 'valid_until' => date('Y-m-d', strtotime('+30 days'))])));
    }
    public function store(Request $r) {
        $this->need('sales.create');
        $d = $this->validated($r);
        $q = DB::transaction(function () use ($d) {
            $q = M\Quotation::create($d['head'] + ['quotation_no' => SequenceService::next('quotation'), 'status' => 'draft', 'prepared_by' => Auth::id()]);
            $this->saveLines($q, $d['lines']);
            return $q;
        });
        return redirect()->route('quotations.show', $q)->with('success', 'Quotation '.$q->quotation_no.' created.');
    }
    public function edit(int $id) {
        $this->need('sales.edit');
        $q = M\Quotation::with('lines')->findOrFail($id);
        abort_unless(in_array($q->status, ['draft', 'sent']), 403, 'Only draft/sent quotations can be edited.');
        return view('docs.quotation.form', $this->formData($q));
    }
    public function update(Request $r, int $id) {
        $this->need('sales.edit');
        $q = M\Quotation::findOrFail($id);
        abort_unless(in_array($q->status, ['draft', 'sent']), 403, 'Only draft/sent quotations can be edited.');
        $d = $this->validated($r);
        DB::transaction(function () use ($q, $d) {
            $q->update($d['head']);
            $q->lines()->delete();
            $this->saveLines($q, $d['lines']);
        });
        return redirect()->route('quotations.show', $q)->with('success', 'Quotation updated.');
    }
    public function destroy(int $id) {
        $this->need('sales.delete');
        $q = M\Quotation::findOrFail($id);
        abort_unless($q->status === 'draft', 403, 'Only drafts can be deleted.');
        $q->delete();
        return redirect()->route('quotations.index')->with('success', 'Quotation deleted.');
    }
    public function send(int $id) {
        $this->need('sales.edit');
        $q = M\Quotation::findOrFail($id);
        abort_unless($q->status === 'draft', 403, 'Only drafts can be sent.');
        $q->update(['status' => 'sent']);
        ApprovalService::request('quotation', $q->id, $q->quotation_no);
        return back()->with('success', 'Quotation sent for approval.');
    }
    public function convert(int $id) {
        $this->need('sales.create');
        $q = M\Quotation::with('lines')->findOrFail($id);
        abort_unless(in_array($q->status, ['approved', 'sent']), 403, 'Only approved/sent quotations can convert.');
        $o = DB::transaction(function () use ($q) {
            $o = M\SalesOrder::create(['order_no' => SequenceService::next('sales_order'), 'order_date' => date('Y-m-d'), 'customer_id' => $q->customer_id,
                'quotation_id' => $q->id, 'quarry_id' => $q->quarry_id, 'subtotal' => $q->subtotal, 'discount_amount' => $q->discount_amount,
                'tax_amount' => $q->levy_nhil + $q->levy_getfund + $q->levy_covid + $q->vat_amount, 'grand_total' => $q->grand_total,
                'status' => 'confirmed', 'created_by' => Auth::id(), 'approved_by' => Auth::id()]);
            foreach ($q->lines as $l) $o->lines()->create(['product_id' => $l->product_id, 'qty_ordered' => $l->qty_tonnes, 'qty_dispatched' => 0, 'rate' => $l->rate, 'amount' => $l->amount]);
            $q->update(['status' => 'converted']);
            return $o;
        });
        return redirect()->route('sales-orders.show', $o)->with('success', 'Converted to sales order '.$o->order_no.'.');
    }
    public function print(Request $r, int $id) {
        $this->need('sales.view');
        $doc = M\Quotation::with('customer', 'lines.product.unit')->findOrFail($id);
        if ($r->get('pdf')) return \App\Services\PdfService::download('docs.quotation.print', ['q' => $doc], 'QT-'.($doc->quotation_no ?? $id).'.pdf');
        return view('docs.quotation.print', ['q' => $doc]);
    }
    protected function validated(Request $r): array {
        $head = $r->validate(['customer_id' => 'required|exists:customers,id', 'quotation_date' => 'required|date', 'valid_until' => 'nullable|date',
            'quarry_id' => 'nullable|exists:quarries,id', 'price_list_id' => 'nullable|exists:price_lists,id', 'subject' => 'nullable|max:255',
            'discount_amount' => 'nullable|numeric|min:0', 'terms' => 'nullable|max:2000',
            'lines' => 'required|array|min:1', 'lines.*.product_id' => 'required|exists:products,id', 'lines.*.qty_tonnes' => 'required|numeric|min:0.001',
            'lines.*.rate' => 'required|numeric|min:0', 'lines.*.discount' => 'nullable|numeric|min:0', 'lines.*.description' => 'nullable|max:255'] + $this->fxRules());
        $lines = $head['lines']; unset($head['lines']);
        return ['head' => $head, 'lines' => $lines];
    }
    protected function saveLines(M\Quotation $q, array $lines): void {
        $sub = 0;
        foreach ($lines as $l) {
            $amt = round($l['qty_tonnes'] * $l['rate'] - ($l['discount'] ?? 0), 2);
            $q->lines()->create(['product_id' => $l['product_id'], 'description' => $l['description'] ?? null, 'qty_tonnes' => $l['qty_tonnes'], 'rate' => $l['rate'], 'discount' => $l['discount'] ?? 0, 'amount' => $amt]);
            $sub += $amt;
        }
        $base = round($sub - (float) ($q->discount_amount ?? 0), 2);
        $tax = GhanaTaxService::salesTax(max(0, $base));
        $q->update(['subtotal' => round($sub, 2), 'levy_nhil' => $tax['nhil'], 'levy_getfund' => $tax['getfund'], 'levy_covid' => $tax['covid'], 'vat_amount' => $tax['vat'], 'grand_total' => $tax['grand']]);
    }
    protected function formData(M\Quotation $q): array {
        return ['fx' => \App\Services\CurrencyService::active(), 'record' => $q, 'isNew' => !$q->exists, 'cfg' => CrudRegistry::get('quotations'), 'key' => 'quotations',
            'docNo' => $q->exists ? $q->quotation_no : SequenceService::peek('quotation'),
            'customers' => M\Customer::where('is_active', true)->orderBy('name')->get(), 'quarries' => M\Quarry::orderBy('name')->get(),
            'products' => M\Product::where('is_active', true)->where('is_sellable', true)->orderBy('name')->get(),
            'priceLists' => M\PriceList::where('is_active', true)->orderBy('name')->get(),
            'tax' => ['nhil' => GhanaTaxService::rate('NHIL', 2.5), 'getfund' => GhanaTaxService::rate('GETFUND', 2.5), 'covid' => GhanaTaxService::rate('COVID', 1), 'vat' => GhanaTaxService::rate('VAT', 15)]];
    }
}
