<?php
declare(strict_types=1);

namespace App\Modules\SportsActivity\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\Pagination;
use App\Modules\SportsActivity\Models\Locker;
use App\Modules\SportsActivity\Models\LockerRental;

class LockerRentalController extends Controller
{
    public function index(Request $request): Response
    {
        $this->authorize('sa.locker_rental.view');

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

        $search = trim((string) $request->get('q', ''));
        $status = trim((string) $request->get('status', ''));
        $page = max(1, (int) $request->get('page', 1));
        $perPage = 25;

        $where = ['lr.is_archived = 0'];
        $params = [];

        if ($search !== '') {
            $where[] = '(lr.rental_number LIKE ? OR p.full_name_ar LIKE ? OR l.code LIKE ?)';
            $params[] = "%{$search}%";
            $params[] = "%{$search}%";
            $params[] = "%{$search}%";
        }
        if ($status !== '') {
            $where[] = 'lr.status = ?';
            $params[] = $status;
        }

        $whereSql = implode(' AND ', $where);

        $total = (int) $db->selectOne(
            "SELECT COUNT(*) as cnt
             FROM sa_locker_rentals lr
             LEFT JOIN sa_players p ON p.id = lr.player_id
             LEFT JOIN sa_lockers l ON l.id = lr.locker_id
             WHERE {$whereSql}",
            $params
        )['cnt'];

        $pagination = Pagination::paginate($total, $perPage, $page);
        $offset = ($page - 1) * $perPage;

        $rentals = $db->select(
            "SELECT lr.*, p.full_name_ar as player_name, l.code as locker_code, l.name_ar as locker_name
             FROM sa_locker_rentals lr
             LEFT JOIN sa_players p ON p.id = lr.player_id
             LEFT JOIN sa_lockers l ON l.id = lr.locker_id
             WHERE {$whereSql}
             ORDER BY lr.created_at DESC
             LIMIT {$perPage} OFFSET {$offset}",
            $params
        );

        // Stats
        $stats = [
            'active' => (int) $db->selectOne("SELECT COUNT(*) as cnt FROM sa_locker_rentals WHERE status = 'active' AND is_archived = 0")['cnt'],
            'grace_period' => (int) $db->selectOne("SELECT COUNT(*) as cnt FROM sa_locker_rentals WHERE status = 'grace_period' AND is_archived = 0")['cnt'],
            'pending_eviction' => (int) $db->selectOne("SELECT COUNT(*) as cnt FROM sa_locker_rentals WHERE status = 'pending_eviction' AND is_archived = 0")['cnt'],
        ];
        $totalLockers = (int) $db->selectOne("SELECT COUNT(*) as cnt FROM sa_lockers WHERE is_active = 1 AND is_archived = 0")['cnt'];
        $occupiedLockers = (int) $db->selectOne(
            "SELECT COUNT(DISTINCT locker_id) as cnt FROM sa_locker_rentals WHERE status IN ('active','grace_period','pending_eviction') AND is_archived = 0"
        )['cnt'];
        $stats['available'] = $totalLockers - $occupiedLockers;

        return $this->view('SportsActivity.Views.locker-rentals.index', [
            'rentals'       => $rentals,
            'pagination'    => $pagination,
            'search'        => $search,
            'status'        => $status,
            'stats'         => $stats,
            'statusOptions' => LockerRental::getStatusOptions(),
            'rentalTypeOptions' => LockerRental::getRentalTypeOptions(),
        ]);
    }

    public function create(Request $request): Response
    {
        $this->authorize('sa.locker_rental.create');

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

        // Available lockers (active and not currently rented)
        $lockers = $db->select(
            "SELECT l.id, l.code, l.name_ar, l.locker_type
             FROM sa_lockers l
             WHERE l.is_active = 1 AND l.is_archived = 0
               AND l.id NOT IN (
                   SELECT locker_id FROM sa_locker_rentals
                   WHERE status IN ('active','grace_period','pending_eviction') AND is_archived = 0
               )
             ORDER BY l.code"
        );

        $players = [];
        $session = App::getInstance()->session();
        $oldInput = $session->get('_old_input', []);
        $oldPlayerId = (int) ($oldInput['player_id'] ?? 0);
        if ($oldPlayerId > 0) {
            $players = $db->select(
                "SELECT id, full_name_ar, registration_serial FROM sa_players WHERE id = ?",
                [$oldPlayerId]
            );
        }

        return $this->view('SportsActivity.Views.locker-rentals.create', [
            'lockers'           => $lockers,
            'players'           => $players,
            'rentalTypeOptions' => LockerRental::getRentalTypeOptions(),
        ]);
    }

    public function store(Request $request): Response
    {
        $this->authorize('sa.locker_rental.create');

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

        $lockerId = (int) $request->post('locker_id', 0);
        $playerId = (int) $request->post('player_id', 0);
        $rentalType = trim((string) $request->post('rental_type', ''));
        $startDate = trim((string) $request->post('start_date', ''));
        $amount = trim((string) $request->post('amount', ''));
        $notes = trim((string) $request->post('notes', ''));

        // Validation
        $errors = [];
        if ($lockerId <= 0) {
            $errors[] = 'يجب اختيار لوكر';
        }
        if ($playerId <= 0) {
            $errors[] = 'يجب اختيار لاعب';
        }
        if ($rentalType === '' || !array_key_exists($rentalType, LockerRental::getRentalTypeOptions())) {
            $errors[] = 'نوع الإيجار مطلوب';
        }
        if ($startDate === '') {
            $errors[] = 'تاريخ البداية مطلوب';
        }
        if ($amount === '' || (float) $amount <= 0) {
            $errors[] = 'المبلغ مطلوب ويجب أن يكون أكبر من صفر';
        }

        // Check locker is available
        if ($lockerId > 0) {
            $occupied = $db->selectOne(
                "SELECT id FROM sa_locker_rentals WHERE locker_id = ? AND status IN ('active','grace_period','pending_eviction') AND is_archived = 0 LIMIT 1",
                [$lockerId]
            );
            if ($occupied) {
                $errors[] = 'هذا اللوكر مشغول بالفعل';
            }
        }

        // Check player exists
        if ($playerId > 0) {
            $player = $db->selectOne("SELECT id FROM sa_players WHERE id = ? AND is_archived = 0", [$playerId]);
            if (!$player) {
                $errors[] = 'اللاعب غير موجود';
            }
        }

        if (!empty($errors)) {
            $session = App::getInstance()->session();
            $alerts = array_map(fn($msg) => ['type' => 'error', 'message' => $msg], $errors);
            $session->flash('_alerts', $alerts);
            $session->flash('_old_input', $request->all());
            return $this->redirect('/sa/locker-rentals/create');
        }

        // Calculate end date
        $endDate = $this->calculateEndDate($startDate, $rentalType);

        $rental = LockerRental::create([
            'rental_number'  => LockerRental::generateNumber(),
            'locker_id'      => $lockerId,
            'player_id'      => $playerId,
            'rental_type'    => $rentalType,
            'start_date'     => $startDate,
            'end_date'       => $endDate,
            'amount'         => (float) $amount,
            'payment_status' => 'unpaid',
            'status'         => 'active',
            'notes'          => $notes ?: null,
        ]);

        return $this->redirect('/sa/locker-rentals')->withSuccess('تم إنشاء إيجار اللوكر بنجاح');
    }

    public function show(Request $request, string $id): Response
    {
        $this->authorize('sa.locker_rental.view');

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

        $rental = $db->selectOne(
            "SELECT lr.*, p.full_name_ar as player_name, p.registration_serial as player_code,
                    l.code as locker_code, l.name_ar as locker_name, l.locker_type,
                    e.full_name_ar as eviction_by_name
             FROM sa_locker_rentals lr
             LEFT JOIN sa_players p ON p.id = lr.player_id
             LEFT JOIN sa_lockers l ON l.id = lr.locker_id
             LEFT JOIN employees e ON e.id = lr.eviction_by
             WHERE lr.id = ? AND lr.is_archived = 0",
            [(int) $id]
        );

        if (!$rental) {
            return $this->redirect('/sa/locker-rentals')->withError('الإيجار غير موجود');
        }

        // Renewal chain
        $renewals = $db->select(
            "SELECT lr.id, lr.rental_number, lr.start_date, lr.end_date, lr.status
             FROM sa_locker_rentals lr
             WHERE (lr.renewed_from_id = ? OR lr.id = ?) AND lr.is_archived = 0
             ORDER BY lr.start_date",
            [(int) $id, (int) ($rental['renewed_from_id'] ?? 0)]
        );

        return $this->view('SportsActivity.Views.locker-rentals.show', [
            'rental'            => $rental,
            'renewals'          => $renewals,
            'statusOptions'     => LockerRental::getStatusOptions(),
            'rentalTypeOptions' => LockerRental::getRentalTypeOptions(),
        ]);
    }

    public function renew(Request $request, string $id): Response
    {
        $this->authorize('sa.locker_rental.create');

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

        $rental = $db->selectOne(
            "SELECT lr.*, p.full_name_ar as player_name, l.code as locker_code, l.name_ar as locker_name
             FROM sa_locker_rentals lr
             LEFT JOIN sa_players p ON p.id = lr.player_id
             LEFT JOIN sa_lockers l ON l.id = lr.locker_id
             WHERE lr.id = ? AND lr.status IN ('active','grace_period') AND lr.is_archived = 0",
            [(int) $id]
        );

        if (!$rental) {
            return $this->redirect('/sa/locker-rentals')->withError('الإيجار غير موجود أو لا يمكن تجديده');
        }

        return $this->view('SportsActivity.Views.locker-rentals.renew', [
            'rental'            => $rental,
            'rentalTypeOptions' => LockerRental::getRentalTypeOptions(),
        ]);
    }

    public function storeRenew(Request $request, string $id): Response
    {
        $this->authorize('sa.locker_rental.create');

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

        $rental = $db->selectOne(
            "SELECT * FROM sa_locker_rentals WHERE id = ? AND status IN ('active','grace_period') AND is_archived = 0",
            [(int) $id]
        );

        if (!$rental) {
            return $this->redirect('/sa/locker-rentals')->withError('الإيجار غير موجود أو لا يمكن تجديده');
        }

        $rentalType = trim((string) $request->post('rental_type', ''));
        $startDate = trim((string) $request->post('start_date', ''));
        $amount = trim((string) $request->post('amount', ''));
        $notes = trim((string) $request->post('notes', ''));

        // Validation
        $errors = [];
        if ($rentalType === '' || !array_key_exists($rentalType, LockerRental::getRentalTypeOptions())) {
            $errors[] = 'نوع الإيجار مطلوب';
        }
        if ($startDate === '') {
            $errors[] = 'تاريخ البداية مطلوب';
        }
        if ($amount === '' || (float) $amount <= 0) {
            $errors[] = 'المبلغ مطلوب ويجب أن يكون أكبر من صفر';
        }

        if (!empty($errors)) {
            $session = App::getInstance()->session();
            $alerts = array_map(fn($msg) => ['type' => 'error', 'message' => $msg], $errors);
            $session->flash('_alerts', $alerts);
            $session->flash('_old_input', $request->all());
            return $this->redirect("/sa/locker-rentals/{$id}/renew");
        }

        $endDate = $this->calculateEndDate($startDate, $rentalType);

        // Mark old rental as completed
        $db->update('sa_locker_rentals', [
            'status'     => 'completed',
            'updated_at' => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        // Create new rental
        $newRental = LockerRental::create([
            'rental_number'  => LockerRental::generateNumber(),
            'locker_id'      => (int) $rental['locker_id'],
            'player_id'      => (int) $rental['player_id'],
            'rental_type'    => $rentalType,
            'start_date'     => $startDate,
            'end_date'       => $endDate,
            'amount'         => (float) $amount,
            'payment_status' => 'unpaid',
            'status'         => 'active',
            'renewed_from_id' => (int) $id,
            'notes'          => $notes ?: null,
        ]);

        return $this->redirect('/sa/locker-rentals/' . $newRental->id)->withSuccess('تم تجديد الإيجار بنجاح');
    }

    public function evict(Request $request, string $id): Response
    {
        $this->authorize('sa.locker_rental.evict');

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

        $rental = $db->selectOne(
            "SELECT lr.*, p.full_name_ar as player_name, l.code as locker_code, l.name_ar as locker_name
             FROM sa_locker_rentals lr
             LEFT JOIN sa_players p ON p.id = lr.player_id
             LEFT JOIN sa_lockers l ON l.id = lr.locker_id
             WHERE lr.id = ? AND lr.status IN ('grace_period','pending_eviction') AND lr.is_archived = 0",
            [(int) $id]
        );

        if (!$rental) {
            return $this->redirect('/sa/locker-rentals')->withError('الإيجار غير موجود أو لا يمكن إجراء محضر فض');
        }

        return $this->view('SportsActivity.Views.locker-rentals.evict', [
            'rental' => $rental,
        ]);
    }

    public function storeEvict(Request $request, string $id): Response
    {
        $this->authorize('sa.locker_rental.evict');

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

        $rental = $db->selectOne(
            "SELECT * FROM sa_locker_rentals WHERE id = ? AND status IN ('grace_period','pending_eviction') AND is_archived = 0",
            [(int) $id]
        );

        if (!$rental) {
            return $this->redirect('/sa/locker-rentals')->withError('الإيجار غير موجود أو لا يمكن إجراء محضر فض');
        }

        $reason = trim((string) $request->post('eviction_reason', ''));

        if ($reason === '') {
            $session = App::getInstance()->session();
            $session->flash('_alerts', [['type' => 'error', 'message' => 'سبب الإخلاء (محضر الفض) مطلوب']]);
            $session->flash('_old_input', $request->all());
            return $this->redirect("/sa/locker-rentals/{$id}/evict");
        }

        $employeeId = App::getInstance()->session()->get('employee_id');

        $db->update('sa_locker_rentals', [
            'status'           => 'evicted',
            'evicted_at'       => date('Y-m-d'),
            'eviction_reason'  => $reason,
            'eviction_by'      => $employeeId ? (int) $employeeId : null,
            'updated_at'       => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        return $this->redirect('/sa/locker-rentals/' . $id)->withSuccess('تم إجراء محضر الفض بنجاح');
    }

    private function calculateEndDate(string $startDate, string $rentalType): string
    {
        $start = new \DateTime($startDate);
        switch ($rentalType) {
            case 'monthly':
                $start->modify('+1 month');
                break;
            case '6_months':
                $start->modify('+6 months');
                break;
            case 'yearly':
                $start->modify('+1 year');
                break;
            default:
                $start->modify('+1 month');
        }
        return $start->format('Y-m-d');
    }
}
