<?php
declare(strict_types=1);

namespace App\Modules\Rentals\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\Rentals\Models\RentalContract;
use App\Modules\Rentals\Models\RentalBooking;
use App\Modules\Rules\Services\RuleEngine;

final class RentalContractService
{
    /**
     * Create a new rental contract.
     *
     * Generates the contract number, calculates totals (subtotal = units * rate),
     * applies bulk discount if eligible, and calculates deposit.
     */
    public static function createContract(array $data): object
    {
        $contractNumber = RentalContract::generateNumber();

        $totalUnits = (int) ($data['total_units'] ?? 0);
        $unitRate   = (float) ($data['unit_rate'] ?? 0);
        $subtotal   = $totalUnits * $unitRate;

        // Calculate discount
        $startDate = $data['start_date'] ?? '';
        $endDate   = $data['end_date'] ?? '';
        $months    = 0;
        if ($startDate && $endDate) {
            $start  = new \DateTimeImmutable($startDate);
            $end    = new \DateTimeImmutable($endDate);
            $diff   = $start->diff($end);
            $months = ($diff->y * 12) + $diff->m + ($diff->d > 0 ? 1 : 0);
        }

        $discountPercentage = self::calculateBulkDiscount($totalUnits, $months);
        $discountAmount     = round($subtotal * ($discountPercentage / 100), 2);
        $totalAmount        = $subtotal - $discountAmount;

        // Calculate deposit
        $depositPercentage = (float) ($data['deposit_percentage'] ?? 0);
        $depositAmount     = round($totalAmount * ($depositPercentage / 100), 2);

        $contract = RentalContract::create([
            'contract_number'            => $contractNumber,
            'entity_id'                  => (int) $data['entity_id'],
            'facility_id'                => (int) $data['facility_id'],
            'activity_type'              => $data['activity_type'] ?? null,
            'start_date'                 => $startDate,
            'end_date'                   => $endDate,
            'total_units'                => $totalUnits,
            'unit_rate'                  => $unitRate,
            'time_tier'                  => $data['time_tier'] ?? 'AM',
            'subtotal'                   => $subtotal,
            'discount_percentage'        => $discountPercentage,
            'discount_amount'            => $discountAmount,
            'total_amount'               => $totalAmount,
            'deposit_percentage'         => $depositPercentage,
            'deposit_amount'             => $depositAmount,
            'deposit_status'             => 'pending',
            'technical_report_submitted' => 0,
            'status'                     => 'draft',
            'terms_json'                 => $data['terms_json'] ?? null,
            'notes'                      => $data['notes'] ?? null,
        ]);

        EventBus::dispatch('rental.contract_created', [
            'contract_id' => (int) $contract->id,
            'entity_id'   => (int) $data['entity_id'],
        ]);

        Logger::info('Rental contract created', ['contract_id' => $contract->id, 'number' => $contractNumber]);

        return $contract;
    }

    /**
     * Activate a rental contract.
     */
    public static function activateContract(int $contractId): void
    {
        $contract = RentalContract::find($contractId);
        if (!$contract) {
            throw new \RuntimeException('Contract not found');
        }

        $contract->update(['status' => 'active']);

        EventBus::dispatch('rental.contract_activated', [
            'contract_id' => $contractId,
        ]);

        Logger::info('Rental contract activated', ['contract_id' => $contractId]);
    }

    /**
     * Generate booking slots from a schedule array.
     *
     * @param int   $contractId
     * @param array $schedule Array of [{date, start_time, end_time}]
     */
    public static function generateBookingSlots(int $contractId, array $schedule): void
    {
        $contract = RentalContract::find($contractId);
        if (!$contract) {
            throw new \RuntimeException('Contract not found');
        }

        $facilityId = (int) ($contract->facility_id ?? $contract['facility_id']);

        foreach ($schedule as $slot) {
            RentalBooking::create([
                'contract_id'  => $contractId,
                'facility_id'  => $facilityId,
                'booking_date' => $slot['date'],
                'start_time'   => $slot['start_time'],
                'end_time'     => $slot['end_time'],
                'status'       => 'scheduled',
            ]);
        }

        Logger::info('Rental booking slots generated', [
            'contract_id' => $contractId,
            'count'       => count($schedule),
        ]);
    }

    /**
     * Calculate bulk discount based on total units and contract duration.
     *
     * Default: if units >= 24 AND months >= 2, return 15%.
     * Values are read from business_rules: RENTAL_BULK_MIN_UNITS,
     * RENTAL_BULK_MIN_MONTHS, RENTAL_BULK_DISCOUNT_PCT.
     */
    public static function calculateBulkDiscount(int $totalUnits, int $months): float
    {
        $minUnits    = (int) (RuleEngine::getValue('RENTAL_BULK_MIN_UNITS') ?? 24);
        $minMonths   = (int) (RuleEngine::getValue('RENTAL_BULK_MIN_MONTHS') ?? 2);
        $discountPct = (float) (RuleEngine::getValue('RENTAL_BULK_DISCOUNT_PCT') ?? 15.00);

        if ($totalUnits >= $minUnits && $months >= $minMonths) {
            return $discountPct;
        }

        return 0.00;
    }
}
