<?php

namespace App\Http\Controllers\Admin;

use App\Actions\Suppliers\CreateSupplier;
use App\Actions\Suppliers\DeleteSupplier;
use App\Actions\Suppliers\ExportSuppliers;
use App\Actions\Suppliers\UpdateSupplier;
use App\Exceptions\SupplierHasBalance;
use App\Http\Controllers\Concerns\RespondsJsonOrRedirect;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\SupplierRequest;
use App\Models\Supplier;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

/**
 * Suppliers admin — CRUD per `docs/features/suppliers-purchases.md`
 * §3. The header KPIs (lifetime spend, outstanding, last order) sit
 * at zero in this slice; Purchases / Payments slices wire the live
 * numbers. The supplier-detail's Purchases/Payments/Returns tabs
 * stay as placeholders until those slices land.
 */
class SupplierController extends Controller
{
    use RespondsJsonOrRedirect;

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

        $q       = trim((string) $request->query('q', ''));
        $status  = (string) $request->query('status', 'all');

        $suppliers = Supplier::query()
            ->when($status === 'active',   fn ($qb) => $qb->where('is_active', true))
            ->when($status === 'inactive', fn ($qb) => $qb->where('is_active', false))
            ->when($q !== '', function ($qb) use ($q) {
                $qb->where(function ($w) use ($q) {
                    $w->where('name', 'like', "%{$q}%")
                      ->orWhere('code', 'like', "%{$q}%")
                      ->orWhere('phone', 'like', "%{$q}%")
                      ->orWhere('email', 'like', "%{$q}%")
                      ->orWhere('business_name', 'like', "%{$q}%")
                      ->orWhere('contact_person', 'like', "%{$q}%");
                });
            })
            // DESC default — newest suppliers first (system convention
            // for tables without a manual `sort_order`).
            ->orderByDesc('id')
            ->get();

        // Summary cards — computed from the same filtered collection.
        $summaryCards = [
            ['label' => __('suppliers.summary.total'),   'value' => number_format($suppliers->count())],
            ['label' => __('suppliers.summary.payable'), 'value' => format_money($suppliers->sum('outstanding_balance')), 'tone' => 'warning'],
            ['label' => __('suppliers.summary.active'),  'value' => number_format($suppliers->where('is_active', true)->count()), 'tone' => 'positive'],
        ];

        return view('admin.suppliers.index', [
            'suppliers'    => $suppliers,
            'summaryCards' => $summaryCards,
            'filters'      => compact('q', 'status'),
        ]);
    }

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

        $supplier = new Supplier([
            'is_active' => true,
        ]);

        return view('admin.suppliers.edit', $this->editorPayload($supplier));
    }

    public function store(SupplierRequest $request, CreateSupplier $create): JsonResponse|RedirectResponse
    {
        $this->authorize('create', Supplier::class);

        $supplier = $create($request->supplierData(), $request->user());

        return $this->jsonOrRedirect(
            $request,
            __('suppliers.flash.created', ['name' => $supplier->name]),
            route('admin.suppliers.index'),
        );
    }

    public function show(Supplier $supplier): View
    {
        $this->authorize('view', $supplier);

        $supplier->load('creator:id,name');

        return view('admin.suppliers.show', [
            'supplier' => $supplier,
        ]);
    }

    public function edit(Supplier $supplier): View
    {
        $this->authorize('update', $supplier);

        return view('admin.suppliers.edit', $this->editorPayload($supplier));
    }

    public function update(SupplierRequest $request, Supplier $supplier, UpdateSupplier $update): JsonResponse|RedirectResponse
    {
        $this->authorize('update', $supplier);

        $update($supplier, $request->supplierData(), $request->user());

        return $this->jsonOrRedirect(
            $request,
            __('suppliers.flash.updated', ['name' => $supplier->name]),
            route('admin.suppliers.index'),
        );
    }

    /**
     * AJAX flip of `is_active` without opening the edit page. Mirrors
     * the customers + products pattern.
     */
    public function toggleActive(Supplier $supplier, Request $request): JsonResponse
    {
        $this->authorize('update', $supplier);

        $willDeactivate = $supplier->is_active;
        if ($willDeactivate) {
            // Same guard as DeleteSupplier — open purchases keep the
            // supplier "in use", so they can't be silently retired
            // mid-flow. Activating doesn't need this check.
            $openCount = \App\Models\Purchase::query()
                ->where('supplier_id', $supplier->getKey())
                ->whereIn('status', [
                    \App\Models\Purchase::STATUS_DRAFT,
                    \App\Models\Purchase::STATUS_SUBMITTED,
                    \App\Models\Purchase::STATUS_RECEIVED,
                    \App\Models\Purchase::STATUS_PARTIALLY_PAID,
                ])
                ->count();
            if ($openCount > 0) {
                return response()->json([
                    'ok'      => false,
                    'message' => __('suppliers.errors.has_open_purchases', ['name' => $supplier->name, 'count' => $openCount]),
                ], 422);
            }
        }

        $supplier->update([
            'is_active'  => ! $supplier->is_active,
            'updated_by' => $request->user()?->id,
        ]);

        return response()->json([
            'ok'        => true,
            'is_active' => (bool) $supplier->is_active,
            'message'   => __($supplier->is_active ? 'suppliers.flash.activated' : 'suppliers.flash.deactivated', ['name' => $supplier->name]),
        ]);
    }

    public function destroy(Request $request, Supplier $supplier, DeleteSupplier $delete): JsonResponse|RedirectResponse
    {
        $this->authorize('delete', $supplier);

        $name = $supplier->name;
        try {
            $delete($supplier);
        } catch (SupplierHasBalance $e) {
            return $this->jsonOrError(
                $request,
                __('suppliers.errors.has_balance', ['amount' => format_money($e->amount)]),
                route('admin.suppliers.show', $supplier),
            );
        } catch (\App\Exceptions\SupplierHasOpenPurchases $e) {
            return $this->jsonOrError(
                $request,
                __('suppliers.errors.has_open_purchases', ['name' => $name, 'count' => $e->count]),
                route('admin.suppliers.show', $supplier),
            );
        }

        return $this->jsonOrRedirect(
            $request,
            __('suppliers.flash.deleted', ['name' => $name]),
            route('admin.suppliers.index'),
        );
    }

    public function export(Request $request, ExportSuppliers $export): \Symfony\Component\HttpFoundation\StreamedResponse
    {
        $this->authorize('viewAny', Supplier::class);

        $format = $request->query('format', 'csv');
        if (! in_array($format, ['csv', 'xlsx'], true)) {
            abort(422, 'Unsupported export format. Use csv or xlsx.');
        }

        return ($export)($format);
    }

    /** @return array<string, mixed> */
    private function editorPayload(Supplier $supplier): array
    {
        return [
            'supplier'       => $supplier,
            'countries'      => \App\Support\Countries::all(),
            'currencies'     => \Illuminate\Support\Facades\DB::table('currencies')
                                    ->orderBy('code')->get(['code', 'name', 'symbol']),
            'defaultCountry' => \App\Models\Company::current()?->country_code
                                ?? \App\Models\Store::query()->value('country_code')
                                ?? 'IN',
            'baseCurrency'   => \App\Models\Company::current()?->base_currency_code ?? 'USD',
        ];
    }
}
