<?php

namespace App\Services;

use App\Models\Attendance;
use App\Models\EarlyLeaveRequest;
use App\Models\Company;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Str;

class EarlyLeaveService
{
    /**
     * Create a new early leave request
     */
    public function createRequest(array $data, User $user): EarlyLeaveRequest
    {
        $company = $user->company;
        $requestDate = Carbon::parse($data['request_date']);
        $isBackdateMode = $company->backdate_enabled ?? false;

        // Get existing attendance for this date
        $attendance = Attendance::where('user_id', $user->id)
            ->whereDate('date', $requestDate)
            ->first();

        // Validate quota if not in backdate mode
        if (!$isBackdateMode) {
            $this->validateQuota($user, $company);

            // Check if already has pending/approved request for this date
            $existingRequest = EarlyLeaveRequest::forUser($user->id)
                ->forDate($requestDate)
                ->active()
                ->first();

            if ($existingRequest) {
                throw new \Exception('Anda sudah memiliki pengajuan izin pulang cepat untuk tanggal ini');
            }
        }

        // Validate reason type
        if (!array_key_exists($data['reason_type'], EarlyLeaveRequest::REASON_TYPES)) {
            throw new \Exception('Tipe alasan tidak valid');
        }

        // Prepare request data
        $requestData = [
            'id' => Str::uuid(),
            'user_id' => $user->id,
            'company_id' => $company->id,
            'attendance_id' => $attendance?->id,
            'request_date' => $requestDate,
            'planned_leave_time' => $data['planned_leave_time'],
            'reason_type' => $data['reason_type'],
            'reason_detail' => $data['reason_detail'] ?? null,
            'status' => EarlyLeaveRequest::STATUS_PENDING,
        ];

        // Handle backdate mode - auto approve
        if ($isBackdateMode) {
            $requestData['status'] = EarlyLeaveRequest::STATUS_APPROVED;
            $requestData['is_auto_approved'] = true;
            $requestData['approved_at'] = $this->generateNaturalApprovalTimestamp($requestDate);
            $requestData['simulated_request_at'] = $data['simulated_request_at'] ?? $this->generateNaturalRequestTimestamp($requestDate, $data['planned_leave_time']);
        }

        $request = EarlyLeaveRequest::create($requestData);

        return $request->fresh(['user', 'attendance', 'approver']);
    }

    /**
     * Approve an early leave request
     */
    public function approve(EarlyLeaveRequest $request, User $approver): EarlyLeaveRequest
    {
        if (!$request->isPending()) {
            throw new \Exception('Pengajuan ini sudah diproses sebelumnya');
        }

        $request->update([
            'status' => EarlyLeaveRequest::STATUS_APPROVED,
            'approved_by' => $approver->id,
            'approved_at' => now(),
        ]);

        return $request->fresh(['user', 'attendance', 'approver']);
    }

    /**
     * Reject an early leave request
     */
    public function reject(EarlyLeaveRequest $request, User $approver, ?string $reason = null): EarlyLeaveRequest
    {
        if (!$request->isPending()) {
            throw new \Exception('Pengajuan ini sudah diproses sebelumnya');
        }

        $request->update([
            'status' => EarlyLeaveRequest::STATUS_REJECTED,
            'approved_by' => $approver->id,
            'approved_at' => now(),
            'rejection_reason' => $reason,
        ]);

        return $request->fresh(['user', 'attendance', 'approver']);
    }

    /**
     * Mark request as used (when user actually checks out early)
     */
    public function markAsUsed(EarlyLeaveRequest $request, ?string $attendanceId = null): EarlyLeaveRequest
    {
        if (!$request->isApproved()) {
            throw new \Exception('Izin belum disetujui');
        }

        $request->update([
            'status' => EarlyLeaveRequest::STATUS_USED,
            'actual_checkout_at' => now(),
            'attendance_id' => $attendanceId ?? $request->attendance_id,
        ]);

        return $request->fresh();
    }

    /**
     * Get status for user (for today)
     */
    public function getStatus(User $user): array
    {
        $company = $user->company;
        $today = today();
        $isBackdateMode = $company->backdate_enabled ?? false;

        // Check for approved request today
        $approvedRequest = EarlyLeaveRequest::forUser($user->id)
            ->forDate($today)
            ->approved()
            ->first();

        // Check for pending request today
        $pendingRequest = EarlyLeaveRequest::forUser($user->id)
            ->forDate($today)
            ->pending()
            ->first();

        // Check if user can checkout early today
        $canCheckoutEarly = $approvedRequest !== null && $approvedRequest->canBeUsed();

        // Get quota info
        $quotaInfo = $this->getQuotaInfo($user);

        return [
            'can_checkout_early' => $canCheckoutEarly,
            'is_backdate_mode' => $isBackdateMode,
            'approved_request' => $approvedRequest ? $this->formatRequest($approvedRequest) : null,
            'pending_request' => $pendingRequest ? $this->formatRequest($pendingRequest) : null,
            'quota_used' => $quotaInfo['quota_used'],
            'quota_max' => $quotaInfo['quota_max'],
            'quota_remaining' => $quotaInfo['quota_remaining'],
            'quota_period' => $quotaInfo['quota_period'],
        ];
    }

    /**
     * Validate quota for early leave requests
     */
    protected function validateQuota(User $user, Company $company): void
    {
        $quotaMax = $company->early_leave_quota_max;
        if ($quotaMax === null) {
            return; // No limit
        }

        $quotaPeriod = $company->early_leave_quota_period ?? 'monthly';
        $usedCount = $this->getQuotaUsed($user, $quotaPeriod);

        if ($usedCount >= $quotaMax) {
            throw new \Exception("Kuota izin pulang cepat Anda sudah habis untuk periode ini ({$usedCount}/{$quotaMax})");
        }
    }

    /**
     * Get quota usage for user
     */
    public function getQuotaUsed(User $user, string $period): int
    {
        $query = EarlyLeaveRequest::forUser($user->id)
            ->whereIn('status', [
                EarlyLeaveRequest::STATUS_PENDING,
                EarlyLeaveRequest::STATUS_APPROVED,
                EarlyLeaveRequest::STATUS_USED,
            ]);

        switch ($period) {
            case 'daily':
                $query->whereDate('created_at', today());
                break;
            case 'weekly':
                $query->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()]);
                break;
            case 'monthly':
                $query->whereMonth('created_at', now()->month)
                      ->whereYear('created_at', now()->year);
                break;
            case 'yearly':
                $query->whereYear('created_at', now()->year);
                break;
        }

        return $query->count();
    }

    /**
     * Get quota info for user
     */
    public function getQuotaInfo(User $user): array
    {
        $company = $user->company;
        $quotaMax = $company->early_leave_quota_max;
        $quotaPeriod = $company->early_leave_quota_period ?? 'monthly';

        if ($quotaMax === null) {
            return [
                'quota_max' => null,
                'quota_used' => 0,
                'quota_remaining' => null,
                'quota_period' => $quotaPeriod,
                'has_limit' => false,
            ];
        }

        $quotaUsed = $this->getQuotaUsed($user, $quotaPeriod);

        return [
            'quota_max' => $quotaMax,
            'quota_used' => $quotaUsed,
            'quota_remaining' => max(0, $quotaMax - $quotaUsed),
            'quota_period' => $quotaPeriod,
            'has_limit' => true,
        ];
    }

    /**
     * Format request for API response
     */
    protected function formatRequest(EarlyLeaveRequest $request): array
    {
        return [
            'id' => $request->id,
            'request_date' => $request->request_date->format('Y-m-d'),
            'request_date_formatted' => $request->request_date->translatedFormat('l, d F Y'),
            'planned_leave_time' => $request->planned_leave_time?->format('H:i'),
            'reason_type' => $request->reason_type,
            'reason_type_label' => $request->reason_type_label,
            'reason_detail' => $request->reason_detail,
            'full_reason' => $request->full_reason,
            'status' => $request->status,
            'status_label' => $request->status_label,
            'approver_name' => $request->approver?->name,
            'approved_at' => $request->approved_at?->toIso8601String(),
            'approved_at_formatted' => $request->approved_at?->translatedFormat('d M Y H:i'),
            'rejection_reason' => $request->rejection_reason,
            'actual_checkout_at' => $request->actual_checkout_at?->toIso8601String(),
            'created_at' => $request->created_at->toIso8601String(),
            'created_at_formatted' => $request->created_at->translatedFormat('d M Y H:i'),
        ];
    }

    /**
     * Generate natural request timestamp for backdate mode
     */
    protected function generateNaturalRequestTimestamp(Carbon $targetDate, string $plannedLeaveTime): Carbon
    {
        // Request time should be before the planned leave time
        $plannedTime = Carbon::parse($plannedLeaveTime);
        $minHour = 8;
        $maxHour = min(16, $plannedTime->hour - 1);

        if ($maxHour <= $minHour) {
            $maxHour = $minHour;
        }

        $hour = rand($minHour, $maxHour);
        $minute = rand(0, 59);

        return $targetDate->copy()->setTime($hour, $minute, rand(0, 59));
    }

    /**
     * Generate natural approval timestamp for backdate mode
     */
    protected function generateNaturalApprovalTimestamp(Carbon $targetDate): Carbon
    {
        // Approval: same day, but after request (simulate quick approval)
        $hour = rand(9, 16);
        $minute = rand(0, 59);

        return $targetDate->copy()->setTime($hour, $minute, rand(0, 59));
    }
}
