<?php
declare(strict_types=1);

namespace App\Modules\SportsActivity\Controllers;

use App\Core\App;
use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Modules\Members\Services\MembershipValidationService;
use App\Modules\Members\Services\NationalIdParser;
use App\Modules\SportsActivity\Services\BookingService;
use App\Modules\SportsActivity\Services\PricingCalculatorService;
use App\Modules\SportsActivity\Services\SlotAvailabilityService;
use App\Modules\Cashier\Services\PaymentRequestService;

class BookingWizardController extends Controller
{
    public function index(Request $request): Response
    {
        $this->authorize('sa.booking_wizard.use');

        $db = App::getInstance()->db();

        $recentBookings = $db->select(
            "SELECT b.id, b.booking_number, b.booker_name, b.booker_type, b.booker_national_id,
                    b.booking_date, b.start_time, b.end_time, b.total_amount, b.payment_status, b.status,
                    fu.name_ar as unit_name, f.name_ar as facility_name
             FROM sa_bookings b
             LEFT JOIN sa_facility_units fu ON fu.id = b.facility_unit_id
             LEFT JOIN sa_facilities f ON f.id = fu.facility_id
             WHERE b.booking_type = 'hourly'
             ORDER BY b.id DESC LIMIT 20"
        );

        return $this->view('SportsActivity.Views.bookings.wizard', [
            'recentBookings' => $recentBookings,
        ]);
    }

    public function lookup(Request $request): Response
    {
        $this->authorize('sa.booking_wizard.use');

        $nationalId = trim((string) $request->post('national_id', ''));
        $membershipNumber = trim((string) $request->post('membership_number', ''));
        $name = trim((string) $request->post('name', ''));

        if ($nationalId === '' && $membershipNumber === '' && $name === '') {
            return $this->json(['success' => false, 'error' => 'أدخل رقم العضوية أو الرقم القومي أو الاسم']);
        }

        $result = [
            'success'           => true,
            'national_id'       => $nationalId,
            'membership_number' => $membershipNumber,
            'effective_type'    => 'non_member',
            'is_member'         => false,
            'member_id'         => null,
            'reason'            => null,
            'name'              => $name,
            'phone'             => null,
            'gender'            => null,
            'date_of_birth'     => null,
            'age'               => null,
        ];

        $membership = null;

        if ($membershipNumber !== '') {
            $membership = MembershipValidationService::checkByMembershipNumber($membershipNumber);
        } elseif ($nationalId !== '' && strlen($nationalId) === 14) {
            $nidParsed = NationalIdParser::parse($nationalId);
            if ($nidParsed && ($nidParsed['is_valid'] ?? false)) {
                $result['date_of_birth'] = $nidParsed['dob'] ?? null;
                $result['age'] = $nidParsed['age_years'] ?? null;
                $result['gender'] = $nidParsed['gender'] ?? null;
            }
            $membership = MembershipValidationService::checkByNationalId($nationalId);
        }

        if ($membership) {
            $result['effective_type'] = $membership['effective_type'];
            $result['is_member'] = $membership['is_active_member'];
            $result['member_id'] = $membership['member_id'];
            $result['reason'] = $membership['reason'];

            if ($membership['found'] && $membership['member']) {
                $m = $membership['member'];
                $result['name'] = $m['full_name_ar'] ?? $result['name'];
                $result['phone'] = $m['phone_mobile'] ?? null;
                $result['membership_number'] = $m['membership_number'] ?? null;
                $result['national_id'] = $m['national_id'] ?? $result['national_id'];
                if (!empty($m['date_of_birth'])) {
                    $result['date_of_birth'] = $m['date_of_birth'];
                    $result['age'] = (int) date_diff(date_create($m['date_of_birth']), date_create('today'))->y;
                }
                if (!empty($m['gender'])) {
                    $result['gender'] = $m['gender'];
                }
            }
        }

        return $this->json($result);
    }

    public function units(Request $request): Response
    {
        $this->authorize('sa.booking_wizard.use');

        $db = App::getInstance()->db();

        $units = $db->select(
            "SELECT fu.id, fu.code, fu.name_ar, fu.unit_type, fu.booking_mode, fu.max_capacity, fu.expected_capacity,
                    f.id as facility_id, f.name_ar as facility_name, f.facility_type, f.operating_hours_json
             FROM sa_facility_units fu
             JOIN sa_facilities f ON f.id = fu.facility_id
             WHERE fu.is_active = 1 AND f.is_archived = 0
             ORDER BY f.name_ar, fu.name_ar"
        );

        $grouped = [];
        foreach ($units as $u) {
            $fId = (int) $u['facility_id'];
            if (!isset($grouped[$fId])) {
                $grouped[$fId] = [
                    'id'              => $fId,
                    'name'            => $u['facility_name'],
                    'type'            => $u['facility_type'],
                    'operating_hours' => json_decode($u['operating_hours_json'] ?: '{}', true),
                    'units'           => [],
                ];
            }
            $grouped[$fId]['units'][] = [
                'id'                => (int) $u['id'],
                'code'              => $u['code'],
                'name'              => $u['name_ar'],
                'unit_type'         => $u['unit_type'],
                'booking_mode'      => $u['booking_mode'],
                'max_capacity'      => (int) $u['max_capacity'],
                'expected_capacity' => (int) ($u['expected_capacity'] ?? 1),
            ];
        }

        return $this->json(['success' => true, 'facilities' => array_values($grouped)]);
    }

    public function slots(Request $request): Response
    {
        $this->authorize('sa.booking_wizard.use');

        $unitId = (int) $request->get('unit_id', 0);
        $date = trim((string) $request->get('date', date('Y-m-d')));

        if ($unitId <= 0) {
            return $this->json(['success' => false, 'error' => 'اختر الوحدة']);
        }

        $db = App::getInstance()->db();

        $unit = $db->selectOne(
            "SELECT fu.*, f.operating_hours_json, f.id as fac_id
             FROM sa_facility_units fu
             JOIN sa_facilities f ON f.id = fu.facility_id
             WHERE fu.id = ? AND fu.is_active = 1",
            [$unitId]
        );

        if (!$unit) {
            return $this->json(['success' => false, 'error' => 'الوحدة غير موجودة']);
        }

        $hours = json_decode($unit['operating_hours_json'] ?: '{}', true);
        $start = $hours['start'] ?? '06:00';
        $end = $hours['end'] ?? '22:00';
        $slotMinutes = (int) ($hours['slot_minutes'] ?? 60);

        $existingBookings = SlotAvailabilityService::getUnitScheduleForDate($unitId, $date);

        $blackouts = $db->select(
            "SELECT start_time, end_time FROM sa_blackout_dates
             WHERE (facility_id = ? OR facility_unit_id = ?) AND blackout_date = ?",
            [(int) $unit['fac_id'], $unitId, $date]
        );

        $slots = [];
        $current = strtotime($date . ' ' . $start);
        $endTs = strtotime($date . ' ' . $end);

        while ($current < $endTs) {
            $slotStart = date('H:i', $current);
            $slotEnd = date('H:i', $current + $slotMinutes * 60);

            $status = 'free';
            $remaining = (int) $unit['max_capacity'];
            $bookerInfo = null;

            foreach ($blackouts as $bo) {
                if ($bo['start_time'] === null || ($slotStart >= $bo['start_time'] && $slotStart < $bo['end_time'])) {
                    $status = 'blackout';
                    $remaining = 0;
                    break;
                }
            }

            if ($status === 'free') {
                $occupiedSpots = 0;
                foreach ($existingBookings as $bk) {
                    if ($bk['start_time'] < $slotEnd && $bk['end_time'] > $slotStart) {
                        $occupiedSpots += (int) ($bk['spots_reserved'] ?? 1);
                        $bookerInfo = $bk['booker_name'] ?? $bk['group_name'] ?? null;
                    }
                }

                if ($unit['booking_mode'] === 'exclusive') {
                    if ($occupiedSpots > 0) {
                        $status = 'occupied';
                        $remaining = 0;
                    }
                } else {
                    $remaining = (int) $unit['max_capacity'] - $occupiedSpots;
                    if ($remaining <= 0) {
                        $status = 'occupied';
                        $remaining = 0;
                    } elseif ($occupiedSpots > 0) {
                        $status = 'partial';
                    }
                }
            }

            $slots[] = [
                'start_time'         => $slotStart,
                'end_time'           => $slotEnd,
                'status'             => $status,
                'remaining_capacity' => $remaining,
                'booker'             => $status !== 'free' ? $bookerInfo : null,
            ];

            $current += $slotMinutes * 60;
        }

        return $this->json([
            'success'           => true,
            'unit_name'         => $unit['name_ar'],
            'booking_mode'      => $unit['booking_mode'],
            'max_capacity'      => (int) $unit['max_capacity'],
            'expected_capacity' => (int) ($unit['expected_capacity'] ?? 1),
            'slots'             => $slots,
        ]);
    }

    public function book(Request $request): Response
    {
        $this->authorize('sa.booking_wizard.use');

        $data = $request->all();
        $validator = new \App\Core\Validator();
        $result = $validator->validate($data, [
            'unit_id'      => 'required|integer',
            'date'         => 'required|date',
            'start_time'   => 'required|string',
            'end_time'     => 'required|string',
            'participants' => 'required|integer|min:1',
            'booker_name'  => 'required|string|min:2|max:200',
        ]);
        if ($result->fails()) {
            return $this->json(['success' => false, 'error' => 'بيانات الحجز غير مكتملة']);
        }

        $unitId = (int) $request->post('unit_id', 0);
        $date = trim((string) $request->post('date', ''));
        $startTime = trim((string) $request->post('start_time', ''));
        $endTime = trim((string) $request->post('end_time', ''));
        $participants = (int) $request->post('participants', 1);
        $bookerName = trim((string) $request->post('booker_name', ''));
        $nationalId = trim((string) $request->post('national_id', ''));
        $isMember = (bool) $request->post('is_member', false);
        $memberId = (int) $request->post('member_id', 0);
        $organizationName = trim((string) $request->post('organization_name', ''));
        $organizationContact = trim((string) $request->post('organization_contact', ''));
        $participantMode = trim((string) $request->post('participant_mode', 'passes'));

        $branch = App::getInstance()->currentBranch();

        $bookerType = $request->post('booker_type', '');
        if ($bookerType === '') {
            $bookerType = $isMember ? 'member' : 'guest';
        }

        $bookingResult = BookingService::createHourlyBooking([
            'facility_unit_id'     => $unitId,
            'booking_date'         => $date,
            'start_time'           => $startTime,
            'end_time'             => $endTime,
            'participant_count'    => $participants,
            'spots_reserved'       => $participants,
            'booker_type'          => $bookerType,
            'booker_id'            => $memberId > 0 ? $memberId : null,
            'booker_name'          => $bookerName,
            'organization_name'    => $organizationName ?: null,
            'organization_contact' => $organizationContact ?: null,
            'participant_mode'     => $participantMode,
            'notes'                => null,
            'branch_id'            => $branch ? (int) $branch['id'] : null,
        ]);

        if (!$bookingResult['success']) {
            return $this->json($bookingResult);
        }

        $bookingId = $bookingResult['booking_id'];

        if ($nationalId !== '') {
            $db = App::getInstance()->db();
            $db->update('sa_bookings', ['booker_national_id' => $nationalId], 'id = ?', [$bookingId]);
        }

        $totalAmount = (float) $bookingResult['total_amount'];

        if ($totalAmount > 0) {
            $payResult = PaymentRequestService::createRequest([
                'member_id'           => $memberId,
                'payment_type'        => 'hourly_booking',
                'amount'              => (string) $totalAmount,
                'description_ar'      => 'حجز ساعي — ' . $bookerName,
                'related_entity_type' => 'sa_bookings',
                'related_entity_id'   => $bookingId,
            ]);

            if ($payResult['success']) {
                $db = App::getInstance()->db();
                $db->update('sa_bookings', [
                    'payment_status' => 'pending',
                    'updated_at'     => date('Y-m-d H:i:s'),
                ], 'id = ?', [$bookingId]);
            }
        }

        return $this->json([
            'success'        => true,
            'booking_id'     => $bookingId,
            'booking_number' => $bookingResult['booking_number'],
            'total_amount'   => $totalAmount,
            'pricing'        => $bookingResult['pricing'] ?? null,
        ]);
    }
}
