<?php

namespace Modules\Bms\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\Bms\Entities\BmsAsset;
use Modules\Bms\Entities\BmsHall;
use Modules\Bms\Services\Contracts\AssetServiceContract;
use Yajra\DataTables\Facades\DataTables;

/**
 * Asset register (P1, Release 2 §5.5). Trackable fixed assets with identity
 * (code/QR), current location/hall, condition and a full movement history.
 * Every relocation goes through AssetServiceContract so the audit is never
 * paper — manual moves here, transfer moves on acceptance in the staff app.
 */
class AssetController extends BmsBaseController
{
    public function index()
    {
        $this->guard('bms.assets.view');

        if (request()->ajax()) {
            $locations = $this->locations();
            $halls = $this->hallsList();

            $assets = BmsAsset::where('business_id', $this->businessId())
                ->select(['id', 'code', 'name', 'name_ar', 'category', 'location_id',
                    'hall_id', 'condition', 'status', 'quantity', 'unit_value']);

            return DataTables::of($assets)
                ->editColumn('category', fn ($a) => $this->categories()[$a->category] ?? $a->category)
                ->addColumn('placement', fn ($a) => $a->hall_id
                    ? ($halls[$a->hall_id] ?? '—')
                    : ($locations[$a->location_id] ?? __('bms::lang.unassigned')))
                ->editColumn('condition', fn ($a) => '<span class="label '.$this->conditionClass($a->condition).'">'
                    .($this->conditions()[$a->condition] ?? $a->condition).'</span>')
                ->editColumn('status', fn ($a) => '<span class="label '.$this->statusClass($a->status).'">'
                    .($this->statuses()[$a->status] ?? $a->status).'</span>')
                ->editColumn('unit_value', fn ($a) => $a->unit_value !== null ? number_format((float) $a->unit_value, 2) : '—')
                ->addColumn('action', function ($a) {
                    $can = auth()->user()->can('bms.assets.manage');
                    $hist = '<a href="'.route('bms.assets.history', $a->id).'" class="tw-dw-btn tw-dw-btn-xs tw-dw-btn-outline tw-dw-btn-info"><i class="fa fas fa-history"></i> '.__('bms::lang.history').'</a>';
                    $label = '<a href="'.route('bms.assets.label', $a->id).'" target="_blank" class="tw-dw-btn tw-dw-btn-xs tw-dw-btn-outline tw-dw-btn-secondary"><i class="fa fas fa-qrcode"></i> '.__('bms::lang.label').'</a>';
                    if (! $can) {
                        return $hist.' '.$label;
                    }
                    $edit = '<button data-href="'.route('bms.assets.edit', $a->id).'" class="tw-dw-btn tw-dw-btn-xs tw-dw-btn-outline tw-dw-btn-primary bms-modal-btn"><i class="glyphicon glyphicon-edit"></i> '.__('messages.edit').'</button>';
                    $move = '<button data-href="'.route('bms.assets.relocate.form', $a->id).'" class="tw-dw-btn tw-dw-btn-xs tw-dw-btn-outline tw-dw-btn-warning bms-modal-btn"><i class="fa fas fa-dolly"></i> '.__('bms::lang.relocate').'</button>';
                    $del = '<button data-href="'.route('bms.assets.destroy', $a->id).'" class="tw-dw-btn tw-dw-btn-xs tw-dw-btn-outline tw-dw-btn-error bms-delete"><i class="glyphicon glyphicon-trash"></i> '.__('messages.delete').'</button>';
                    return $edit.' '.$move.' '.$hist.' '.$label.' '.$del;
                })
                ->rawColumns(['condition', 'status', 'action'])
                ->make(true);
        }

        return view('bms::assets.index');
    }

    public function create()
    {
        $this->guard('bms.assets.manage');
        return view('bms::assets.create', $this->formData());
    }

    public function store(Request $request)
    {
        $this->guard('bms.assets.manage');
        $data = $this->validateAsset($request);

        try {
            $hallId = $data['hall_id'] ?? null;
            $locationId = $hallId
                ? optional(BmsHall::where('business_id', $this->businessId())->find($hallId))->location_id
                : ($data['location_id'] ?? null);

            app(AssetServiceContract::class)->register($this->businessId(), array_merge($data, [
                'location_id' => $locationId,
                'hall_id'     => $hallId,
                'moved_by'    => $this->userId(),
            ]));

            return $this->ok(__('bms::lang.added_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    public function edit($id)
    {
        $this->guard('bms.assets.manage');
        $asset = BmsAsset::where('business_id', $this->businessId())->findOrFail($id);
        return view('bms::assets.edit', array_merge($this->formData(), compact('asset')));
    }

    /** Edit attributes only — location/condition changes go through relocate(). */
    public function update(Request $request, $id)
    {
        $this->guard('bms.assets.manage');
        $data = $this->validateAsset($request, false);

        try {
            $asset = BmsAsset::where('business_id', $this->businessId())->findOrFail($id);
            $asset->update([
                'code'         => $data['code'] ?: $asset->code,
                'name'         => $data['name'],
                'name_ar'      => $data['name_ar'] ?? null,
                'category'     => $data['category'] ?? 'other',
                'condition'    => $data['condition'] ?? $asset->condition,
                'status'       => $data['status'] ?? $asset->status,
                'quantity'     => (int) ($data['quantity'] ?? 1),
                'unit_value'   => $data['unit_value'] ?? null,
                'serial_no'    => $data['serial_no'] ?? null,
                'purchased_at' => $data['purchased_at'] ?? null,
                'notes'        => $data['notes'] ?? null,
            ]);
            return $this->ok(__('bms::lang.updated_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    public function relocateForm($id)
    {
        $this->guard('bms.assets.manage');
        $asset = BmsAsset::where('business_id', $this->businessId())->findOrFail($id);
        return view('bms::assets.relocate', array_merge($this->formData(), compact('asset')));
    }

    public function relocate(Request $request, $id)
    {
        $this->guard('bms.assets.manage');
        $data = $this->validate($request, [
            'location_id' => 'nullable|integer',
            'hall_id'     => 'nullable|integer',
            'condition'   => 'nullable|string|max:30',
            'notes'       => 'nullable|string|max:255',
        ]);

        try {
            $asset = BmsAsset::where('business_id', $this->businessId())->findOrFail($id);
            $hallId = $data['hall_id'] ?? null;
            $locationId = $hallId
                ? optional(BmsHall::where('business_id', $this->businessId())->find($hallId))->location_id
                : ($data['location_id'] ?? null);

            if (! $locationId) {
                return $this->fail(__('bms::lang.relocate_needs_target'));
            }

            app(AssetServiceContract::class)->transferLocation(
                $this->businessId(), (int) $asset->id, (int) $locationId,
                [
                    'to_hall_id' => $hallId,
                    'condition'  => $data['condition'] ?? $asset->condition,
                    'reason'     => 'manual',
                    'moved_by'   => $this->userId(),
                    'notes'      => $data['notes'] ?? null,
                ]
            );

            return $this->ok(__('bms::lang.relocated_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    public function destroy($id)
    {
        $this->guard('bms.assets.manage');
        try {
            $asset = BmsAsset::where('business_id', $this->businessId())->findOrFail($id);
            DB::table('bms_asset_movements')->where('asset_id', $asset->id)->delete();
            $asset->delete();
            return $this->ok(__('bms::lang.deleted_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    public function history($id)
    {
        $this->guard('bms.assets.view');
        $asset = BmsAsset::where('business_id', $this->businessId())->with('hall:id,name')->findOrFail($id);
        $movements = $asset->movements()->get();
        $locations = $this->locations();
        $halls = $this->hallsList();
        $users = \App\User::where('business_id', $this->businessId())
            ->get(['id', 'first_name', 'surname', 'username'])
            ->mapWithKeys(fn ($u) => [$u->id => trim(($u->first_name ?? '').' '.($u->surname ?? '')) ?: $u->username])
            ->toArray();

        return view('bms::assets.history', compact('asset', 'movements', 'locations', 'halls', 'users'));
    }

    /** Printable QR / code label (uses milon/barcode DNS2D — no new deps). */
    public function label($id)
    {
        $this->guard('bms.assets.view');
        $asset = BmsAsset::where('business_id', $this->businessId())->findOrFail($id);

        $qr = null;
        try {
            $qr = (new \Milon\Barcode\DNS2D())->getBarcodePNG($asset->code, 'QRCODE', 5, 5);
        } catch (\Throwable $e) {
            \Log::warning('[BMS] QR generation failed: '.$e->getMessage());
        }

        return view('bms::assets.label', compact('asset', 'qr'));
    }

    public function reports()
    {
        $this->guard('bms.assets.view');
        $biz = $this->businessId();
        $locations = $this->locations();
        $halls = $this->hallsList();

        $byCategory = BmsAsset::where('business_id', $biz)
            ->select('category', DB::raw('count(*) c'), DB::raw('sum(quantity) q'), DB::raw('sum(unit_value*quantity) v'))
            ->groupBy('category')->get();
        $byCondition = BmsAsset::where('business_id', $biz)
            ->select('condition', DB::raw('count(*) c'), DB::raw('sum(quantity) q'))
            ->groupBy('condition')->get();
        $byStatus = BmsAsset::where('business_id', $biz)
            ->select('status', DB::raw('count(*) c'), DB::raw('sum(quantity) q'))
            ->groupBy('status')->get();
        $byPlacement = BmsAsset::where('business_id', $biz)
            ->select('location_id', 'hall_id', DB::raw('count(*) c'), DB::raw('sum(quantity) q'))
            ->groupBy('location_id', 'hall_id')->get()
            ->map(function ($r) use ($locations, $halls) {
                $r->label = $r->hall_id ? ($halls[$r->hall_id] ?? '—') : ($locations[$r->location_id] ?? __('bms::lang.unassigned'));
                return $r;
            });

        $totalValue = (float) BmsAsset::where('business_id', $biz)->sum(DB::raw('unit_value*quantity'));
        $totalUnits = (int) BmsAsset::where('business_id', $biz)->sum('quantity');
        $totalAssets = (int) BmsAsset::where('business_id', $biz)->count();

        return view('bms::assets.reports', compact(
            'byCategory', 'byCondition', 'byStatus', 'byPlacement',
            'totalValue', 'totalUnits', 'totalAssets'
        ) + ['categories' => $this->categories(), 'conditions' => $this->conditions(), 'statuses' => $this->statuses()]);
    }

    // ---- helpers ---------------------------------------------------------

    protected function validateAsset(Request $request, bool $withPlacement = true): array
    {
        $rules = [
            'code'         => 'nullable|string|max:60',
            'name'         => 'required|string|max:191',
            'name_ar'      => 'nullable|string|max:191',
            'category'     => 'nullable|string|max:40',
            'condition'    => 'nullable|string|max:30',
            'status'       => 'nullable|string|max:30',
            'quantity'     => 'nullable|integer|min:1',
            'unit_value'   => 'nullable|numeric|min:0',
            'serial_no'    => 'nullable|string|max:120',
            'purchased_at' => 'nullable|date',
            'notes'        => 'nullable|string|max:1000',
        ];
        if ($withPlacement) {
            $rules['location_id'] = 'nullable|integer';
            $rules['hall_id'] = 'nullable|integer';
        }
        return $this->validate($request, $rules);
    }

    protected function formData(): array
    {
        return [
            'locations'  => $this->locations(),
            'halls'      => $this->hallsList(),
            'categories' => $this->categories(),
            'conditions' => $this->conditions(),
            'statuses'   => $this->statuses(),
        ];
    }

    /** Halls for the current business as id => "name — venue". */
    protected function hallsList(): array
    {
        return DB::table('bms_halls')
            ->leftJoin('bms_venues', 'bms_venues.id', '=', 'bms_halls.venue_id')
            ->where('bms_halls.business_id', $this->businessId())
            ->orderBy('bms_halls.name')
            ->get(['bms_halls.id', 'bms_halls.name as hall_name', 'bms_venues.name as venue_name'])
            ->mapWithKeys(fn ($h) => [$h->id => trim($h->hall_name . ($h->venue_name ? ' — ' . $h->venue_name : ''))])
            ->toArray();
    }

    protected function categories(): array
    {
        return [
            'seating'  => __('bms::lang.cat_seating'),
            'tables'   => __('bms::lang.cat_tables'),
            'av'       => __('bms::lang.cat_av'),
            'lighting' => __('bms::lang.cat_lighting'),
            'decor'    => __('bms::lang.cat_decor'),
            'linen'    => __('bms::lang.cat_linen'),
            'staging'  => __('bms::lang.cat_staging'),
            'other'    => __('bms::lang.cat_other'),
        ];
    }

    protected function conditions(): array
    {
        return [
            'good'     => __('bms::lang.cond_good'),
            'fair'     => __('bms::lang.cond_fair'),
            'worn'     => __('bms::lang.cond_worn'),
            'damaged'  => __('bms::lang.cond_damaged'),
            'retired'  => __('bms::lang.cond_retired'),
        ];
    }

    protected function statuses(): array
    {
        return [
            'available'   => __('bms::lang.ast_available'),
            'in_use'      => __('bms::lang.ast_in_use'),
            'in_transit'  => __('bms::lang.ast_in_transit'),
            'maintenance' => __('bms::lang.ast_maintenance'),
            'retired'     => __('bms::lang.ast_retired'),
        ];
    }

    protected function conditionClass(string $c): string
    {
        return [
            'good' => 'label-success', 'fair' => 'label-info', 'worn' => 'label-warning',
            'damaged' => 'label-danger', 'retired' => 'label-default',
        ][$c] ?? 'label-default';
    }

    protected function statusClass(string $s): string
    {
        return [
            'available' => 'label-success', 'in_use' => 'label-primary', 'in_transit' => 'label-warning',
            'maintenance' => 'label-danger', 'retired' => 'label-default',
        ][$s] ?? 'label-default';
    }
}
