<?php

namespace App\Services\Administrator;

use App\Libraries\StaffTimeOffLinkService;
use App\Models\StaffAttendance;
use App\Models\User;
use App\Services\SemesterRangeService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class AdministratorAbsenceService
{
    public function __construct(
        protected AdministratorSharedService $shared,
        protected User $userModel,
        protected StaffAttendance $staffAttendanceModel,
        protected SemesterRangeService $semesterRangeService,
        protected StaffTimeOffLinkService $staffTimeOffLinkService,
    ) {
    }

    public function getAbsenceFormData(int $userId): array
    {
        $admin = $this->userModel->find($userId);
        $displayName = $admin
            ? trim(($admin->firstname ?? '') . ' ' . ($admin->lastname ?? ''))
            : 'Administrator';

        $semester = $this->shared->getSemester();
        $schoolYear = $this->shared->getSchoolYear();

        $existing = $this->staffAttendanceModel
            ->where('user_id', $userId)
            ->where('semester', $semester)
            ->where('school_year', $schoolYear)
            ->orderByDesc('date')
            ->get()
            ->toArray();

        return [
            'admin_name' => $displayName,
            'semester' => $semester,
            'schoolYear' => $schoolYear,
            'existing' => $existing,
            'availableDates' => $this->shared->allowedAbsenceDates(),
        ];
    }

    public function submit(Request $request, int $userId): array
    {
        $semester = $this->shared->getSemester();
        $schoolYear = $this->shared->getSchoolYear();

        if ($schoolYear === '') {
            return [
                'success' => false,
                'message' => 'Semester or school year not configured.',
                'status' => 422,
            ];
        }

        $dates = (array) $request->input('dates', []);
        $reasonType = trim((string) $request->input('reason_type', ''));
        $reasonText = trim((string) $request->input('reason', ''));

        if ($reasonText === '') {
            return [
                'success' => false,
                'message' => 'Reason is required.',
                'status' => 422,
            ];
        }

        $reasonBase = $reasonType !== '' ? strtolower($reasonType) : '';
        $reason = $reasonBase !== '' ? ($reasonBase . ': ' . $reasonText) : $reasonText;

        $allowedSet = array_fill_keys($this->shared->allowedAbsenceDates(), true);

        $roleName = method_exists($this->userModel, 'getUserRole')
            ? ($this->userModel->getUserRole($userId) ?: null)
            : null;

        $saved = 0;
        $invalid = [];
        $savedDates = [];

        $dates = array_values(array_unique(array_map('strval', $dates)));

        foreach ($dates as $d) {
            $d = trim($d);
            if ($d === '') {
                continue;
            }

            try {
                $parsed = \Carbon\Carbon::createFromFormat('Y-m-d', $d);
                if ($parsed->format('Y-m-d') !== $d || empty($allowedSet[$d])) {
                    $invalid[] = $d;
                    continue;
                }
            } catch (\Throwable) {
                $invalid[] = $d;
                continue;
            }

            $semesterForDate = $this->semesterRangeService->getSemesterForDate($d);
            if ($semesterForDate === '') {
                $semesterForDate = $semester;
            }

            $ok = $this->staffAttendanceModel->upsertOne(
                userId: $userId,
                roleName: $roleName,
                date: $d,
                semester: $semesterForDate,
                schoolYear: $schoolYear,
                status: StaffAttendance::STATUS_ABSENT,
                reason: $reason,
                editorId: $userId
            );

            if ($ok) {
                $saved++;
                $savedDates[] = $d;
            }
        }

        if (!empty($invalid)) {
            return [
                'success' => false,
                'message' => 'Invalid dates: ' . implode(', ', $invalid),
                'status' => 422,
            ];
        }

        $this->sendPrincipalNotification(
            userId: $userId,
            roleName: $roleName,
            semester: $semester,
            schoolYear: $schoolYear,
            reasonType: $reasonType,
            reasonText: $reasonText,
            dates: $dates,
            savedDates: $savedDates
        );

        return [
            'success' => true,
            'message' => $saved . ' day(s) saved as absent.',
            'saved' => $saved,
            'dates' => $savedDates,
            'status' => 200,
        ];
    }

    protected function sendPrincipalNotification(
        int $userId,
        ?string $roleName,
        string $semester,
        string $schoolYear,
        string $reasonType,
        string $reasonText,
        array $dates,
        array $savedDates
    ): void {
        try {
            $user = $this->userModel->find($userId);
            $fullName = trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) ?: 'Administrator';
            $userEmail = $user->email ?? '';
            $role = $roleName ?: 'admin';
            $dateList = !empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates);

            $subject = sprintf(
                'TimeOff Request: %s (%s) — %s',
                $fullName,
                ucfirst((string) $role),
                $dateList ?: 'No dates'
            );

            $submittedAt = now()->toDateTimeString();

            $body = '<div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:1.5;">'
                . '<h3 style="margin:0 0 8px;">New TimeOff Request</h3>'
                . '<p style="margin:0 0 12px;">A staff time-off request was submitted from the administrator portal.</p>'
                . '<table cellpadding="6" cellspacing="0" style="border-collapse:collapse;">'
                . '<tr><td><strong>Name</strong></td><td>' . e($fullName) . '</td></tr>'
                . '<tr><td><strong>Email</strong></td><td>' . e($userEmail) . '</td></tr>'
                . '<tr><td><strong>Role</strong></td><td>' . e((string) $role) . '</td></tr>'
                . '<tr><td><strong>Semester</strong></td><td>' . e($semester) . '</td></tr>'
                . '<tr><td><strong>School Year</strong></td><td>' . e($schoolYear) . '</td></tr>'
                . '<tr><td><strong>Reason Type</strong></td><td>' . e($reasonType ?: '-') . '</td></tr>'
                . '<tr><td><strong>Reason</strong></td><td>' . e($reasonText) . '</td></tr>'
                . '<tr><td><strong>Dates</strong></td><td>' . e($dateList ?: '-') . '</td></tr>'
                . '<tr><td><strong>Submitted At</strong></td><td>' . e($submittedAt) . '</td></tr>'
                . '</table>'
                . '</div>';

            $token = $this->staffTimeOffLinkService->createToken([
                'uid' => $userId,
                'email' => $userEmail,
                'name' => $fullName,
                'role' => $role,
                'dates' => $dateList ?: '-',
                'reason' => $reasonText,
                'reason_type' => $reasonType,
                'submitted_at' => $submittedAt,
                'origin' => 'administrator portal',
            ]);

            $notifyUrl = url('/timeoff/notify/' . rawurlencode($token));

            $body .= '<p style="margin-top:16px;">Click <a href="' . e($notifyUrl) . '">Send confirmation email to '
                . e($fullName)
                . '</a> so the staff member is notified automatically. This link expires in 14 days.</p>';

            $principalEmail = env('PRINCIPAL_EMAIL', 'principal@alrahmaisgl.org');

            Mail::html($body, function ($message) use ($principalEmail, $subject) {
                $message->to($principalEmail)->subject($subject);
            });
        } catch (\Throwable $e) {
            Log::error('Failed to send TimeOff email (admin): ' . $e->getMessage());
        }
    }
}