<?php

namespace Modules\Bms\Http\Controllers\Api;

use Illuminate\Http\Request;
use Modules\Bms\Entities\BmsAddon;
use Modules\Bms\Entities\BmsBooking;
use Modules\Bms\Entities\BmsChangeRequest;
use Modules\Bms\Entities\BmsDocument;
use Modules\Bms\Entities\BmsLead;
use Modules\Bms\Entities\BmsOfficeVisit;
use Modules\Bms\Entities\BmsPackageItem;
use Modules\Bms\Services\Booking\BookingService;
use Modules\Bms\Services\Booking\CancellationService;
use Modules\Bms\Services\Notifications\NotificationRouter;

/**
 * Authenticated client portal (P3). Guarded by bms.api:client.
 */
class ClientController extends ApiController
{
    public function me(Request $request)
    {
        $contact = $request->attributes->get('bms_owner');
        $businessId = $this->authBusinessId($request);

        $leads = BmsLead::where('business_id', $businessId)
            ->where('contact_id', $contact->id)
            ->with(['selectedHalls.hall:id,name,name_ar', 'selectedHalls.package:id,name,price'])
            ->latest()->get();

        $visits = BmsOfficeVisit::where('business_id', $businessId)
            ->where('contact_id', $contact->id)
            ->orderBy('visit_date')->get();

        $bookings = BmsBooking::where('business_id', $businessId)
            ->where('contact_id', $contact->id)
            ->latest()->get(['id', 'booking_no', 'status', 'event_date', 'total_amount', 'deposit_amount']);

        // Documents the client can view / accept (contracts), keyed for display.
        $bookingIds = $bookings->pluck('id');
        $docs = BmsDocument::where('business_id', $businessId)
            ->whereIn('booking_id', $bookingIds)
            ->whereIn('type', ['contract', 'proposal'])
            ->latest()->get();

        // Editable until a contract exists (contracted/completed booking locks it).
        $locked = $bookings->whereIn('status', ['contracted', 'completed'])->isNotEmpty();

        $changeRequests = BmsChangeRequest::where('business_id', $businessId)
            ->where('contact_id', $contact->id)->latest()->limit(20)->get();

        return $this->ok([
            'contact'  => ['id' => $contact->id, 'name' => $contact->name, 'mobile' => $contact->mobile],
            'editable' => ! $locked,
            'leads'    => $leads->map(fn ($l) => [
                'id'          => $l->id,
                'stage'       => $l->stage,
                'grand_total' => $this->leadTotal($l),
                'halls'       => $this->leadHalls($l),
            ])->values(),
            'visits'   => $visits->map(fn ($v) => [
                'id'         => $v->id,
                'date'       => optional($v->visit_date)->toDateString(),
                'time'       => $v->visit_time,
                'status'     => $v->status,
                'location_id'=> $v->location_id,
            ])->values(),
            'bookings' => $bookings,
            'documents' => $docs->map(fn ($d) => [
                'id'          => $d->id,
                'type'        => $d->type,
                'booking_id'  => $d->booking_id,
                'version'     => $d->version,
                'accepted_at' => optional($d->accepted_at)->toIso8601String(),
            ])->values(),
            'cancellation_policy' => app(CancellationService::class)->policy($businessId),
            'change_requests' => $changeRequests->map(fn ($c) => [
                'id' => $c->id, 'type' => $c->type, 'message' => $c->message,
                'status' => $c->status, 'staff_note' => $c->staff_note,
                'at' => optional($c->created_at)->toIso8601String(),
            ])->values(),
        ]);
    }

    /** Submit a change request (post-contract edits need staff approval). */
    public function changeRequest(Request $request)
    {
        $contact = $request->attributes->get('bms_owner');
        $businessId = $this->authBusinessId($request);
        $data = $request->validate([
            'message' => 'required|string|max:1000',
            'type'    => 'nullable|in:edit,cancel,reschedule,other',
        ]);

        $lead = BmsLead::where('business_id', $businessId)->where('contact_id', $contact->id)->latest()->first();
        $booking = BmsBooking::where('business_id', $businessId)->where('contact_id', $contact->id)->latest()->first();

        $cr = BmsChangeRequest::create([
            'business_id' => $businessId,
            'contact_id'  => $contact->id,
            'lead_id'     => optional($lead)->id,
            'booking_id'  => optional($booking)->id,
            'type'        => $data['type'] ?? 'edit',
            'message'     => $data['message'],
            'status'      => 'pending',
        ]);

        // Alert staff (best effort).
        try {
            app(NotificationRouter::class)->notify(
                $businessId, 'change_request', [],
                'New change request', $contact->name . ': ' . $data['message'],
                ['change_request_id' => $cr->id], 'change_request:' . $cr->id
            );
        } catch (\Throwable $e) {
            \Log::warning('[BMS] change-request notify failed: ' . $e->getMessage());
        }

        return $this->ok(['id' => $cr->id, 'status' => $cr->status]);
    }

    /** Per-hall selection breakdown (package + add-ons + kept items + swaps). */
    protected function leadHalls(BmsLead $lead): array
    {
        $halls = $lead->selectedHalls()->with(['hall:id,name,name_ar', 'package:id,name,name_ar,price'])->get();
        $booker = app(BookingService::class);

        return $halls->map(function ($lh) use ($booker) {
            $addons = collect((array) $lh->addons)->map(function ($a) {
                $addon = BmsAddon::find($a['addon_id'] ?? null);
                return $addon ? ['name' => $addon->name, 'qty' => (int) ($a['qty'] ?? 1), 'price' => (float) $addon->price] : null;
            })->filter()->values();

            $swaps = [];
            $extras = [];
            foreach ((array) $lh->package_items as $pi) {
                if (empty($pi['included'])) {
                    continue;
                }
                $item = BmsPackageItem::find($pi['item_id'] ?? null);
                if (! $item) {
                    continue;
                }
                if (! empty($pi['variant_index']) && is_array($item->options) && isset($item->options[$pi['variant_index'] - 1])) {
                    $o = $item->options[$pi['variant_index'] - 1];
                    $swaps[] = ['item' => $item->name, 'label' => $o['label'] ?? '', 'delta' => (float) ($o['price_delta'] ?? 0)];
                }
                foreach ((array) ($pi['content_swaps'] ?? []) as $cs) {
                    $line = app(\Modules\Bms\Services\Catalog\PackagePresenter::class)->swapLine($item, $cs);
                    $swaps[] = ['item' => $item->name, 'label' => $line['label'], 'delta' => $line['delta']];
                }
                if ($item->is_addon) {
                    $extras[] = ['name' => $item->name, 'qty' => (int) ($pi['qty'] ?? 1), 'price' => (float) ($item->addon_price ?? 0)];
                }
            }

            return [
                'hall'    => optional($lh->hall)->name,
                'package' => optional($lh->package)->name,
                'total'   => $booker->estimateHall($lh),
                'score'   => $lh->score,
                'addons'  => $addons,
                'extras'  => $extras,
                'swaps'   => $swaps,
            ];
        })->all();
    }

    protected function leadTotal(BmsLead $lead): float
    {
        $booker = app(BookingService::class);
        return (float) $lead->selectedHalls()->get()->sum(fn ($lh) => $booker->estimateHall($lh));
    }
}
