<?php

namespace App\Services;

use App\Models\ExtensionRequest;
use App\Models\EmployeeAccessDetail;
use App\Models\RevocationSchedule;
use App\Models\SystemLog;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ExtensionService
{
    protected $telegramService;

    public function __construct(TelegramService $telegramService)
    {
        $this->telegramService = $telegramService;
    }

    /**
     * Create extension request
     */
    public function createRequest(array $data, int $requestedBy): ExtensionRequest
    {
        DB::beginTransaction();

        try {
            // Check for existing pending request
            $existing = ExtensionRequest::where('employee_access_detail_id', $data['employee_access_detail_id'])
                ->where('approval_status', 'pending')
                ->first();

            if ($existing) {
                throw new \Exception('Masih ada permintaan pending untuk akses ini.');
            }

            // Determine approval level
            $approvalLevel = $this->determineApprovalLevel($data['requested_duration_days']);

            // Create request
            $request = ExtensionRequest::create([
                'employee_access_detail_id' => $data['employee_access_detail_id'],
                'requested_by' => $requestedBy,
                'requested_duration_days' => $data['requested_duration_days'],
                'new_expiry_date' => $data['new_expiry_date'],
                'reason' => $data['reason'],
                'supporting_document' => $data['supporting_document'] ?? null,
                'approval_level_required' => $approvalLevel,
                'approval_status' => $approvalLevel === 'none' ? 'approved' : 'pending',
            ]);

            // If no approval needed, auto-approve
            if ($approvalLevel === 'none') {
                $this->approveExtension($request, $requestedBy);
            } else {
                // Notify approvers
                $this->notifyApprovers($request);
            }

            DB::commit();

            Log::info('Extension request created', [
                'request_id' => $request->id,
                'approval_level' => $approvalLevel,
            ]);

            return $request;

        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Approve extension request
     */
    public function approveExtension(ExtensionRequest $request, int $approvedBy): bool
    {
        DB::beginTransaction();

        try {
            // Refresh to get current state and lock the row
            $request = ExtensionRequest::lockForUpdate()->find($request->id);

            if ($request->approval_status !== 'pending') {
                DB::rollBack();
                throw new \Exception('Request sudah diproses.');
            }

            // Check permission
            if (!$this->canApprove($request, $approvedBy)) {
                DB::rollBack();
                throw new \Exception('Anda tidak memiliki izin untuk menyetujui request ini.');
            }

            $accessDetail = $request->employeeAccessDetail;
            $oldValues = $accessDetail->toArray();

            // Update access detail
            $accessDetail->update([
                'current_expiry_date' => $request->new_expiry_date,
                'status' => 'extended',
                'is_extended' => true,
                'extension_count' => $accessDetail->extension_count + 1,
                'last_extended_at' => now(),
                'last_extended_by' => $approvedBy,
            ]);

            // Update request
            $request->update([
                'approval_status' => 'approved',
                'approved_by' => $approvedBy,
                'approved_at' => now(),
            ]);

            // Create new schedule
            $accessDetail->revocationSchedules()->create([
                'scheduled_date' => $request->new_expiry_date,
                'status' => 'scheduled',
            ]);

            // System log
            SystemLog::logExtend(
                $approvedBy,
                'employee_access',
                $accessDetail->id,
                $oldValues,
                $accessDetail->fresh()->toArray()
            );

            // Notify requester
            $this->notifyApproval($request, 'approved');

            DB::commit();

            Log::info('Extension approved', [
                'request_id' => $request->id,
                'access_detail_id' => $accessDetail->id,
                'new_date' => $request->new_expiry_date,
            ]);

            return true;

        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Reject extension request
     */
    public function rejectExtension(ExtensionRequest $request, int $rejectedBy, string $reason): bool
    {
        DB::beginTransaction();

        try {
            // Refresh to get current state and lock the row
            $request = ExtensionRequest::lockForUpdate()->find($request->id);

            if ($request->approval_status !== 'pending') {
                DB::rollBack();
                throw new \Exception('Request sudah diproses.');
            }

            // Check permission
            if (!$this->canApprove($request, $rejectedBy)) {
                DB::rollBack();
                throw new \Exception('Anda tidak memiliki izin untuk menolak request ini.');
            }

            $request->update([
                'approval_status' => 'rejected',
                'approved_by' => $rejectedBy,
                'approved_at' => now(),
                'rejection_reason' => $reason,
            ]);

            // Notify requester
            $this->notifyApproval($request, 'rejected', $reason);

            DB::commit();

            Log::info('Extension rejected', [
                'request_id' => $request->id,
                'rejected_by' => $rejectedBy,
                'reason' => $reason,
            ]);

            return true;

        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Determine approval level based on duration
     */
    protected function determineApprovalLevel(int $days): string
    {
        if ($days > 30) {
            return 'manager_hrd'; // Need manager + HRD approval
        } elseif ($days > 7) {
            return 'manager'; // Need manager approval
        }
        return 'none'; // Auto-approve
    }

    /**
     * Check if user can approve request
     */
    public function canApprove(ExtensionRequest $request, int $userId): bool
    {
        $user = User::find($userId);

        if (!$user) return false;

        // Super admin can approve all
        if ($user->isSuperAdmin()) return true;

        $requiredLevel = $request->approval_level_required;

        switch ($requiredLevel) {
            case 'none':
                return true;

            case 'manager':
                return $user->isManager() || $user->isAdminHR() || $user->isSuperAdmin();

            case 'manager_hrd':
                return $user->isAdminHR() || $user->isSuperAdmin();

            case 'director':
                return $user->role === 'director' || $user->isSuperAdmin();

            default:
                return false;
        }
    }

    /**
     * Get pending requests for user
     */
    public function getPendingForUser(int $userId): array
    {
        $user = User::find($userId);

        if (!$user) return [];

        $query = ExtensionRequest::with([
                'employeeAccessDetail.employee',
                'employeeAccessDetail.accessCatalog',
                'requestedBy'
            ])
            ->where('approval_status', 'pending');

        // Filter based on user role
        if (!$user->isSuperAdmin()) {
            $query->where(function ($q) use ($user) {
                // Manager can see requests from their department
                if ($user->isManager()) {
                    $q->orWhereHas('employeeAccessDetail.employee', function ($sq) use ($user) {
                        $sq->where('department_id', $user->department_id);
                    });
                }

                // HR can see all
                if ($user->isAdminHR()) {
                    $q->orWhere('approval_level_required', 'manager_hrd');
                }
            });
        }

        return $query->latest()->get()->all();
    }

    /**
     * Get extension statistics
     */
    public function getStatistics(string $period = 'monthly'): array
    {
        $query = ExtensionRequest::query();

        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;
        }

        $total = $query->count();
        $approved = (clone $query)->where('approval_status', 'approved')->count();
        $rejected = (clone $query)->where('approval_status', 'rejected')->count();
        $pending = (clone $query)->where('approval_status', 'pending')->count();

        $totalDays = (clone $query)
            ->where('approval_status', 'approved')
            ->sum('requested_duration_days');

        return [
            'total' => $total,
            'approved' => $approved,
            'rejected' => $rejected,
            'pending' => $pending,
            'total_days_extended' => $totalDays,
            'approval_rate' => $total > 0 ? round(($approved / $total) * 100, 2) : 0,
        ];
    }

    /**
     * Notify approvers about new request
     */
    protected function notifyApprovers(ExtensionRequest $request): void
    {
        $accessDetail = $request->employeeAccessDetail;
        $employee = $accessDetail->employee;
        $accessCatalog = $accessDetail->accessCatalog;
        $requester = $request->requestedBy;

        // Get approvers based on level
        $approvers = User::where(function ($query) use ($request) {
            switch ($request->approval_level_required) {
                case 'manager':
                    $query->where('role', 'manager')
                          ->orWhere('role', 'super_admin');
                    break;
                case 'manager_hrd':
                    $query->where('role', 'admin_hr')
                          ->orWhere('role', 'super_admin');
                    break;
                case 'director':
                    $query->where('role', 'director')
                          ->orWhere('role', 'super_admin');
                    break;
            }
        })
        ->where('is_active', true)
        ->get();

        foreach ($approvers as $approver) {
            if ($approver->telegram_chat_id) {
                $this->telegramService->sendExtensionRequest(
                    $approver->telegram_chat_id,
                    $employee->name,
                    $accessCatalog->name,
                    $request->requested_duration_days,
                    $request->reason,
                    $requester->name,
                    $request->id
                );
            }
        }
    }

    /**
     * Notify requester about approval/rejection
     */
    protected function notifyApproval(ExtensionRequest $request, string $status, ?string $reason = null): void
    {
        $requester = $request->requestedBy;
        $accessDetail = $request->employeeAccessDetail;
        $employee = $accessDetail->employee;
        $accessCatalog = $accessDetail->accessCatalog;

        if (!$requester->telegram_chat_id) return;

        if ($status === 'approved') {
            $this->telegramService->sendExtensionApproved(
                $requester->telegram_chat_id,
                $employee->name,
                $accessCatalog->name,
                $request->new_expiry_date->format('d M Y'),
                $request->approvedBy->name ?? 'System'
            );
        } else {
            $this->telegramService->sendExtensionRejected(
                $requester->telegram_chat_id,
                $employee->name,
                $accessCatalog->name,
                $reason ?? 'Tidak ada alasan',
                $request->approvedBy->name ?? 'System'
            );
        }
    }

    /**
     * Cancel extension request
     */
    public function cancelRequest(ExtensionRequest $request, int $cancelledBy): bool
    {
        if ($request->approval_status !== 'pending') {
            throw new \Exception('Hanya request pending yang bisa dibatalkan.');
        }

        if ($request->requested_by !== $cancelledBy && !User::find($cancelledBy)?->isSuperAdmin()) {
            throw new \Exception('Anda tidak memiliki izin membatalkan request ini.');
        }

        $request->update([
            'approval_status' => 'rejected',
            'rejection_reason' => 'Dibatalkan oleh pemohon',
            'approved_by' => $cancelledBy,
            'approved_at' => now(),
        ]);

        Log::info('Extension request cancelled', [
            'request_id' => $request->id,
            'cancelled_by' => $cancelledBy,
        ]);

        return true;
    }
}
