<?php

namespace Modules\Bms\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Modules\Bms\Entities\BmsHall;
use Modules\Bms\Entities\BmsHallAvailability;

class CalendarController extends BmsBaseController
{
    public function index(Request $request)
    {
        $this->guard('bms.calendar.view');

        $halls = BmsHall::where('business_id', $this->businessId())
            ->orderBy('name')->pluck('name', 'id')->toArray();

        return view('bms::calendar.index', ['halls' => $halls]);
    }

    /**
     * Unified activity feed for the smart calendar (FullCalendar): bookings,
     * office visits, holds/blocks and maintenance, colour-coded by type/status,
     * within the requested range and optionally scoped to one hall.
     */
    public function feed(Request $request)
    {
        $this->guard('bms.calendar.view');
        $bid = $this->businessId();
        $start = substr((string) $request->input('start', now()->startOfMonth()->toDateString()), 0, 10);
        $end = substr((string) $request->input('end', now()->endOfMonth()->toDateString()), 0, 10);
        $types = array_filter(explode(',', (string) $request->input('types', 'booking,visit,hold,maintenance')));
        $hallId = (int) $request->input('hall_id') ?: null;
        $locationId = $hallId ? optional(BmsHall::where('business_id', $bid)->find($hallId))->location_id : null;

        $events = [];

        // Bookings (by event_date). Filtered by the actual booked hall when a
        // hall is chosen (via bms_booking_halls) — not by location, so bookings
        // whose location_id is null are never missed. Cancelled bookings are
        // excluded (their day is freed).
        if (in_array('booking', $types, true)) {
            $rows = \DB::table('bms_bookings')
                ->leftJoin('contacts', 'contacts.id', '=', 'bms_bookings.contact_id')
                ->where('bms_bookings.business_id', $bid)
                ->whereNotNull('bms_bookings.event_date')
                ->whereBetween('bms_bookings.event_date', [$start, $end])
                ->where('bms_bookings.status', '!=', 'cancelled')
                ->when($hallId, fn ($q) => $q->whereExists(fn ($s) => $s->selectRaw('1')->from('bms_booking_halls')
                    ->whereColumn('bms_booking_halls.booking_id', 'bms_bookings.id')->where('bms_booking_halls.hall_id', $hallId)))
                ->get([
                    'bms_bookings.id', 'bms_bookings.booking_no', 'bms_bookings.status', 'bms_bookings.event_type',
                    'bms_bookings.event_date', 'bms_bookings.start_time', 'bms_bookings.end_time',
                    'bms_bookings.attendees', 'bms_bookings.total_amount', 'bms_bookings.deposit_amount',
                    'contacts.name as contact_name',
                ]);
            foreach ($rows as $b) {
                $color = in_array($b->status, ['confirmed', 'contracted', 'paid', 'completed'], true) ? '#2e7d32'
                    : (in_array($b->status, ['tentative', 'pending', 'reserved', 'hold', 'inquiry'], true) ? '#e0a008'
                    : '#3c8dbc');
                $events[] = [
                    'id'    => 'booking-' . $b->id,
                    'title' => '🎉 ' . ($b->contact_name ?: ($b->booking_no ?: '#' . $b->id)) . ($b->event_type ? ' · ' . $b->event_type : ''),
                    'start' => $b->event_date . ($b->start_time ? 'T' . $b->start_time : ''),
                    'end'   => ($b->end_time && $b->event_date) ? $b->event_date . 'T' . $b->end_time : null,
                    'allDay' => ! $b->start_time,
                    'backgroundColor' => $color, 'borderColor' => $color,
                    'extendedProps' => [
                        'type' => 'booking', 'status' => $b->status,
                        'url'  => route('bms.bookings.show', $b->id),
                        'info' => trim(($b->booking_no ? $b->booking_no . ' · ' : '') . __('bms::lang.attendees') . ': ' . ($b->attendees ?? '—')
                            . ' · ' . __('bms::lang.deposit') . '/' . __('bms::lang.total') . ': ' . number_format((float) $b->deposit_amount) . '/' . number_format((float) $b->total_amount)),
                    ],
                ];
            }
        }

        // Office visits.
        if (in_array('visit', $types, true)) {
            $rows = \DB::table('bms_office_visits')
                ->leftJoin('contacts', 'contacts.id', '=', 'bms_office_visits.contact_id')
                ->where('bms_office_visits.business_id', $bid)
                ->whereBetween('bms_office_visits.visit_date', [$start, $end])
                ->when($locationId, fn ($q) => $q->where('bms_office_visits.location_id', $locationId))
                ->get(['bms_office_visits.id', 'bms_office_visits.visit_date', 'bms_office_visits.visit_time', 'bms_office_visits.status', 'contacts.name as contact_name']);
            foreach ($rows as $v) {
                $color = $v->status === 'done' ? '#2e7d32' : ($v->status === 'cancelled' ? '#9aa0a6' : ($v->status === 'requested' ? '#e0a008' : '#6f42c1'));
                $events[] = [
                    'id'    => 'visit-' . $v->id,
                    'title' => '🚶 ' . __('bms::lang.visit') . ' · ' . ($v->contact_name ?: '—'),
                    'start' => $v->visit_date . ($v->visit_time ? 'T' . $v->visit_time : ''),
                    'allDay' => ! $v->visit_time,
                    'backgroundColor' => $color, 'borderColor' => $color,
                    'extendedProps' => ['type' => 'visit', 'status' => $v->status, 'info' => $v->status, 'url' => route('bms.visits.show', $v->id)],
                ];
            }
        }

        // Holds / manual blocks (booked/tentative come from bookings to avoid dupes).
        if (in_array('hold', $types, true)) {
            $rows = BmsHallAvailability::where('business_id', $bid)
                ->whereIn('status', ['hold', 'blocked'])
                ->whereBetween('date', [$start, $end])
                ->when($hallId, fn ($q) => $q->where('hall_id', $hallId))
                ->get();
            foreach ($rows as $r) {
                $color = $r->status === 'blocked' ? '#7f8c8d' : '#f39c12';
                $events[] = [
                    'id'    => 'hold-' . $r->id,
                    'title' => ($r->status === 'blocked' ? '🔒 ' : '⏳ ') . __('bms::lang.status_' . $r->status),
                    'start' => $r->date->toDateString(),
                    'allDay' => true,
                    'backgroundColor' => $color, 'borderColor' => $color,
                    'extendedProps' => ['type' => 'hold', 'status' => $r->status, 'avail_id' => $r->id, 'releasable' => true],
                ];
            }
        }

        // Maintenance (by due date).
        if (in_array('maintenance', $types, true)) {
            $rows = \DB::table('bms_maintenance_requests')
                ->where('business_id', $bid)
                ->whereNotNull('due_at')
                ->whereBetween(\DB::raw('DATE(due_at)'), [$start, $end])
                ->when($hallId, fn ($q) => $q->where('hall_id', $hallId))
                ->get(['id', 'code', 'title', 'status', 'priority', 'due_at']);
            foreach ($rows as $m) {
                $done = in_array($m->status, ['resolved', 'verified'], true);
                $color = $done ? '#2e7d32' : ($m->priority === 'urgent' ? '#c0392b' : ($m->priority === 'high' ? '#e67e22' : '#16a085'));
                $events[] = [
                    'id'    => 'maintenance-' . $m->id,
                    'title' => '🔧 ' . ($m->code ? $m->code . ' · ' : '') . $m->title,
                    'start' => substr($m->due_at, 0, 10),
                    'allDay' => true,
                    'backgroundColor' => $color, 'borderColor' => $color,
                    'extendedProps' => [
                        'type' => 'maintenance', 'status' => $m->status, 'priority' => $m->priority,
                        'url' => route('bms.maintenance.show', $m->id),
                    ],
                ];
            }
        }

        return response()->json($events);
    }

    /**
     * Block a hall-date (admin manual block). Uses the same unique
     * (hall_id, date, slot) guard that prevents double-booking.
     */
    public function block(Request $request)
    {
        $this->guard('bms.calendar.view');
        $request->validate([
            'hall_id' => 'required|integer',
            'date'    => 'required|date',
            'slot'    => 'nullable|in:full_day,morning,evening',
            'notes'   => 'nullable|string|max:255',
        ]);

        try {
            $hall = BmsHall::where('business_id', $this->businessId())->findOrFail($request->hall_id);

            $exists = BmsHallAvailability::where('hall_id', $hall->id)
                ->where('date', $request->date)
                ->where('slot', $request->input('slot', 'full_day'))
                ->exists();

            if ($exists) {
                return $this->fail(__('bms::lang.slot_unavailable'));
            }

            BmsHallAvailability::create([
                'business_id' => $this->businessId(),
                'hall_id'     => $hall->id,
                'date'        => $request->date,
                'slot'        => $request->input('slot', 'full_day'),
                'status'      => 'blocked',
                'created_by'  => $this->userId(),
                'notes'       => $request->input('notes'),
            ]);

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

    /**
     * Release a manual block or an expired hold. Confirmed bookings cannot be
     * released here — they're managed through the booking lifecycle.
     */
    public function release($id)
    {
        $this->guard('bms.calendar.view');
        try {
            $row = BmsHallAvailability::where('business_id', $this->businessId())->findOrFail($id);
            if (in_array($row->status, ['booked', 'tentative'], true)) {
                return $this->fail(__('bms::lang.cannot_release_booked'));
            }
            $row->delete();
            return $this->ok(__('bms::lang.success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }
}
