<?php

namespace App\Http\Controllers\Company\Inventory;

use App\Http\Controllers\Controller;
use App\Models\{Account, AuditLog, Item, ItemCategory, ItemPriceLevel, PriceLevel, Uom, Warehouse};
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class ItemsController extends Controller
{
    public function index(Request $request)
    {
        $this->gate('inventory', 'view');

        $query = Item::with(['category','uom']);

        if ($request->filled('search')) {
            $s = $request->search;
            $query->where(fn($q) =>
                $q->where('name',    'like', "%{$s}%")
                  ->orWhere('code',    'like', "%{$s}%")
                  ->orWhere('barcode', 'like', "%{$s}%")
            );
        }
        if ($request->filled('type'))     { $query->where('type', $request->type); }
        if ($request->filled('category')) { $query->where('category_id', $request->category); }
        if ($request->filled('status'))   { $query->where('is_active', $request->status === 'active'); }

        $items = $query->orderBy('code')->paginate(25)->withQueryString();

        $stats = [
            'total'     => Item::count(),
            'active'    => Item::where('is_active', true)->count(),
            'inventory' => Item::where('type', 'inventory')->count(),
            'service'   => Item::where('type', 'service')->count(),
        ];

        // Fix N+1: load categories with item count for filter dropdown
        $categories = ItemCategory::withoutGlobalScopes()
            ->where('company_id', auth()->user()->company_id)
            ->whereNull('deleted_at')
            ->orderBy('name')
            ->get(['id','name','depth']);

        return view('inventory.items.index', compact('items', 'stats', 'categories'));
    }

    public function create()
    {
        $this->gate('inventory', 'create');
        return view('inventory.items.create', $this->formData());
    }

    public function store(Request $request)
    {
        $this->gate('inventory', 'create');

        $companyId = auth()->user()->company_id;
        $validated = $this->validateItem($request, $companyId);

        // FIX: Explicitly handle boolean checkboxes — absent = false
        $validated['is_sold']      = $request->boolean('is_sold');
        $validated['is_purchased'] = $request->boolean('is_purchased');
        $validated['is_active']    = true; // Always active on create

        $item = DB::transaction(function () use ($validated, $companyId, $request) {
            $item = Item::withoutGlobalScopes()->create(array_merge(
                $validated,
                ['company_id' => $companyId]
            ));
            $this->savePriceLevels($item, $request->input('price_levels', []));
            return $item;
        });

        AuditLog::record('create', 'items', (string) $item->id, null,
            ['code' => $item->code, 'name' => $item->name],
            "Item created: {$item->name}");

        return redirect()->route('inventory.items.index')
            ->with('success', "Item '{$item->name}' created successfully.");
    }

    public function edit(Item $item)
    {
        $this->gate('inventory', 'edit');
        $this->sameCompany($item);

        $companyId      = auth()->user()->company_id;
        $priceLevelData = ItemPriceLevel::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('item_id', $item->id)
            ->with('priceLevel', 'currency')
            ->get()
            ->keyBy('price_level_id');

        return view('inventory.items.edit', array_merge(
            $this->formData(),
            compact('item', 'priceLevelData')
        ));
    }

    public function update(Request $request, Item $item)
    {
        $this->gate('inventory', 'edit');
        $this->sameCompany($item);

        $companyId = auth()->user()->company_id;
        $validated = $this->validateItem($request, $companyId, $item->id);
        $old       = $item->only(['code','name','type','is_active']);

        // FIX: Explicitly handle boolean checkboxes — absent means false (unchecked)
        $validated['is_sold']      = $request->boolean('is_sold');
        $validated['is_purchased'] = $request->boolean('is_purchased');
        $validated['is_active']    = $request->boolean('is_active', true);

        DB::transaction(function () use ($item, $validated, $request) {
            $item->update($validated);
            $this->savePriceLevels($item, $request->input('price_levels', []));
        });

        AuditLog::record('update', 'items', (string) $item->id, $old,
            $item->only(['code','name','type','is_active']),
            "Item updated: {$item->name}");

        return redirect()->route('inventory.items.index')
            ->with('success', "Item '{$item->name}' updated successfully.");
    }

    public function toggleActive(Item $item)
    {
        $this->gate('inventory', 'edit');
        $this->sameCompany($item);

        $old = $item->is_active;
        $item->update(['is_active' => !$old]);

        AuditLog::record('status_change', 'items', (string) $item->id,
            ['is_active' => $old], ['is_active' => !$old],
            ($old ? 'Deactivated' : 'Activated') . " item: {$item->name}");

        return back()->with('success', "Item " . (!$old ? 'activated' : 'deactivated') . " successfully.");
    }

    public function destroy(Item $item)
    {
        $this->gate('inventory', 'delete');
        $this->sameCompany($item);

        $guard = app(\App\Services\MasterDeletionGuard::class);
        if ($message = $guard->blockingMessage($item)) {
            return back()->withErrors(['error' => $message]);
        }

        $name = $item->name;
        $id = $item->id;
        $guard->hardDelete($item);

        AuditLog::record('hard_delete', 'items', (string) $id,
            null, null, "Item permanently deleted: {$name}");

        return redirect()->route('inventory.items.index')
            ->with('success', "Item '{$name}' permanently deleted.");
    }

    // ── AJAX: search items for Select2 ────────────────────────────────────────
    public function search(Request $request)
    {
        $companyId    = auth()->user()->company_id;
        $q            = $request->input('q', '');
        $type         = $request->input('type');
        $priceLevelId = (int) $request->input('price_level_id', 0);

        $query = Item::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereNull('deleted_at')
            ->where('is_active', true)
            ->with('uom');

        if ($type === 'sold')      { $query->where('is_sold', true); }
        if ($type === 'purchased') { $query->where('is_purchased', true); }

        if ($q) {
            $query->where(fn($qq) =>
                $qq->where('name',    'like', "%{$q}%")
                   ->orWhere('code',    'like', "%{$q}%")
                   ->orWhere('barcode', 'like', "%{$q}%")
            );
        }

        $items = $query->orderBy('code')->limit(50)->get();

        return response()->json([
            'results' => $items->map(function ($item) use ($priceLevelId) {
                $price = $priceLevelId ? $item->getPriceForLevel($priceLevelId) : null;
                return [
                    'id'         => $item->id,
                    'text'       => ($item->code ? "[{$item->code}] " : '') . $item->name,
                    'uom'        => $item->uom?->code,
                    'type'       => $item->type,
                    'tracking'   => $item->tracking_type,
                    'unit_price' => $price,
                    'valuation'  => $item->valuation_method,
                ];
            })
        ]);
    }

    // ── Helpers ───────────────────────────────────────────────────────────────
    private function savePriceLevels(Item $item, array $priceLevels): void
    {
        $companyId = $item->company_id;

        foreach ($priceLevels as $plId => $data) {
            // Skip if price is empty string (user left it blank)
            if (!isset($data['unit_price']) || $data['unit_price'] === '') continue;

            $unitPrice     = (float) $data['unit_price'];
            $effectiveDate = !empty($data['effective_date']) ? $data['effective_date'] : null;
            $currencyId    = !empty($data['currency_id'])    ? (int) $data['currency_id'] : null;

            ItemPriceLevel::withoutGlobalScopes()->updateOrCreate(
                [
                    'company_id'     => $companyId,
                    'item_id'        => $item->id,
                    'price_level_id' => (int) $plId,
                    'effective_date' => $effectiveDate,
                ],
                [
                    'unit_price'  => $unitPrice,
                    'currency_id' => $currencyId,
                ]
            );
        }
    }

    private function validateItem(Request $request, int $companyId, ?int $ignoreId = null): array
    {
        return $request->validate([
            'code' => [
                'required', 'string', 'max:50',
                Rule::unique('items')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at'))
                    ->ignore($ignoreId),
            ],
            'name'        => 'required|string|max:200',
            'description' => 'nullable|string|max:1000',
            'barcode'     => 'nullable|string|max:100',
            'type'        => 'required|in:inventory,service,non_inventory',

            // FIX: Add company-scoped exists validation for all FK fields
            'category_id' => [
                'nullable', 'integer',
                Rule::exists('item_categories', 'id')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at')),
            ],
            'uom_id' => [
                'nullable', 'integer',
                Rule::exists('uoms', 'id')->where(fn($q) => $q->where('company_id', $companyId)),
            ],
            'default_warehouse_id' => [
                'nullable', 'integer',
                Rule::exists('warehouses', 'id')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at')),
            ],
            'inventory_account_id' => [
                'nullable', 'integer',
                Rule::exists('accounts', 'id')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at')),
            ],
            'cogs_account_id' => [
                'nullable', 'integer',
                Rule::exists('accounts', 'id')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at')),
            ],
            'sales_account_id' => [
                'nullable', 'integer',
                Rule::exists('accounts', 'id')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at')),
            ],
            'purchase_account_id' => [
                'nullable', 'integer',
                Rule::exists('accounts', 'id')
                    ->where(fn($q) => $q->where('company_id', $companyId)->whereNull('deleted_at')),
            ],
            'reorder_level'    => 'nullable|numeric|min:0',
            'opening_stock'    => 'nullable|numeric|min:0',
            'valuation_method' => 'required|in:weighted_average,fifo',
            'tracking_type'    => 'required|in:none,serial,lot,both',
            // Note: is_sold, is_purchased, is_active handled separately via $request->boolean()
        ]);
    }

    private function formData(): array
    {
        $companyId = auth()->user()->company_id;

        $categories = ItemCategory::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereNull('deleted_at')
            ->where('is_active', true)
            ->orderBy('name')
            ->get(['id','name','depth']);

        $uoms = Uom::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->orderBy('code')
            ->get(['id','code','name']);

        $warehouses = Warehouse::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereNull('deleted_at')
            ->where('is_active', true)
            ->orderBy('name')
            ->get(['id','name','depth']);

        $priceLevels = PriceLevel::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->orderBy('name')
            ->get(['id','name','is_default']);

        $currencies = \App\Models\Currency::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->orderBy('code')
            ->get(['id','code','symbol']);

        $accounts = Account::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_group', false)
            ->where('is_active', true)
            ->whereNull('deleted_at')
            ->orderBy('code')
            ->get(['id','code','name','type']);

        return compact('categories','uoms','warehouses','priceLevels','currencies','accounts');
    }

    private function gate(string $module, string $action): void
    {
        if (!auth()->user()->hasPermission($module, $action)) abort(403);
    }

    private function sameCompany(Item $item): void
    {
        if ($item->company_id !== auth()->user()->company_id) abort(403);
    }
}
