<?php

namespace App\Services;

use App\Models\Application;
use App\Models\JobListing;
use App\Models\JobStage;
use App\Models\MessageTemplate;
use App\Models\NotificationLog;
use App\Models\Setting;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class NotificationService
{
    /**
     * Send notification via both Email and WhatsApp (immediate)
     */
    public function send(Application $application, string $type, string $subject, string $message, ?string $waMessage = null): void
    {
        $this->sendEmail($application, $type, $subject, $message);
        $this->sendWhatsApp($application, $type, $waMessage ?? $message);
    }

    /**
     * Schedule notification for later sending (goes to pending queue)
     * Both email and WhatsApp are created as 'scheduled' with a scheduled_at timestamp
     */
    public function schedule(Application $application, string $type, string $subject, string $message, ?string $waMessage = null, ?\DateTimeInterface $scheduledAt = null): array
    {
        $applicant = $application->applicant;

        // Default: schedule based on stage_advance_days setting
        if ($scheduledAt === null) {
            $intervalDays = (int) Setting::get('stage_advance_days', 2);
            $scheduledAt = now()->addDays($intervalDays);
        }

        $logs = [];

        // Schedule email
        $logs[] = NotificationLog::create([
            'application_id' => $application->id,
            'type' => $type,
            'channel' => 'email',
            'status' => 'scheduled',
            'message' => $message,
            'subject' => $subject,
            'recipient_name' => $applicant->name,
            'recipient_contact' => $applicant->email,
            'scheduled_at' => $scheduledAt,
        ]);

        // Schedule WhatsApp
        $logs[] = NotificationLog::create([
            'application_id' => $application->id,
            'type' => $type,
            'channel' => 'whatsapp',
            'status' => 'scheduled',
            'message' => $waMessage ?? $message,
            'wa_message' => $waMessage ?? $message,
            'recipient_name' => $applicant->name,
            'recipient_contact' => $applicant->whatsapp ?? '',
            'scheduled_at' => $scheduledAt,
        ]);

        return $logs;
    }

    /**
     * Process a single scheduled notification log entry (actually send it)
     */
    public function processScheduledLog(NotificationLog $log): bool
    {
        $application = $log->application;
        if (!$application || !$application->applicant) {
            $log->update(['status' => 'failed', 'error' => 'Application or applicant not found']);
            return false;
        }

        // Skip sending rejected notification if admin has already accepted the applicant
        if ($log->type === 'rejected' && $application->status === 'accepted') {
            $log->update(['status' => 'cancelled', 'error' => 'Dibatalkan: pelamar sudah diterima oleh admin']);
            return false;
        }

        // Skip sending accepted notification if status is already rejected (edge case)
        if ($log->type === 'accepted' && $application->status === 'rejected') {
            $log->update(['status' => 'cancelled', 'error' => 'Dibatalkan: pelamar sudah ditolak']);
            return false;
        }

        if ($log->channel === 'email') {
            return $this->sendScheduledEmail($log, $application);
        } elseif ($log->channel === 'whatsapp') {
            return $this->sendScheduledWhatsApp($log, $application);
        }

        return false;
    }

    /**
     * Send a previously scheduled email
     */
    private function sendScheduledEmail(NotificationLog $log, Application $application): bool
    {
        $applicant = $application->applicant;
        $subject = $log->subject ?? "Notifikasi - " . Setting::get('site_name', 'Bursa Kerja');
        $recipientEmail = $this->resolveEmailRecipient($applicant->email ?? null, $log->recipient_contact);
        $recipientName = $this->resolveRecipientName($applicant->name ?? null, $log->recipient_name);

        if ($recipientEmail === null) {
            $log->update(['status' => 'failed', 'error' => 'Email pelamar kosong atau tidak valid']);
            return false;
        }

        try {
            Mail::html($this->buildEmailHtml($recipientName, $log->message, $application), function ($mail) use ($recipientEmail, $recipientName, $subject) {
                $mail->to($recipientEmail, $recipientName)
                    ->subject($subject);
            });

            $log->update(['status' => 'sent', 'sent_at' => now()]);
            return true;
        } catch (\Throwable $e) {
            Log::error('Scheduled email failed: ' . $e->getMessage());
            $log->update(['status' => 'failed', 'error' => $e->getMessage()]);
            return false;
        }
    }

    /**
     * Send a previously scheduled WhatsApp
     */
    private function sendScheduledWhatsApp(NotificationLog $log, Application $application): bool
    {
        $applicant = $application->applicant;
        $apiKey = Setting::get('fonnte_api_key', config('services.fonnte.key'));

        if (!$apiKey) {
            $log->update(['status' => 'failed', 'error' => 'Fonnte API key not configured']);
            return false;
        }

        if (empty($applicant->whatsapp)) {
            $log->update(['status' => 'failed', 'error' => 'Nomor WhatsApp pelamar kosong']);
            return false;
        }

        $message = $log->wa_message ?? $log->message;

        try {
            $response = Http::withHeaders([
                'Authorization' => $apiKey,
            ])->post('https://api.fonnte.com/send', [
                'target' => $applicant->whatsapp,
                'message' => strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $message)),
                'countryCode' => '62',
            ]);

            if ($response->successful() && $response->json('status')) {
                $log->update(['status' => 'sent', 'sent_at' => now()]);
                return true;
            } else {
                $log->update(['status' => 'failed', 'error' => $response->body()]);
                return false;
            }
        } catch (\Throwable $e) {
            Log::error('Scheduled WhatsApp failed: ' . $e->getMessage());
            $log->update(['status' => 'failed', 'error' => $e->getMessage()]);
            return false;
        }
    }

    /**
     * Send email notification via SMTP
     */
    public function sendEmail(Application $application, string $type, string $subject, string $message): void
    {
        $applicant = $application->applicant;
        $recipientEmail = $this->resolveEmailRecipient($applicant->email ?? null, null);
        $recipientName = $this->resolveRecipientName($applicant->name ?? null, null);

        $log = NotificationLog::create([
            'application_id' => $application->id,
            'type' => $type,
            'channel' => 'email',
            'status' => 'pending',
            'subject' => $subject,
            'message' => $message,
            'recipient_name' => $recipientName,
            'recipient_contact' => $recipientEmail ?? '',
        ]);

        if ($recipientEmail === null) {
            $log->update(['status' => 'failed', 'error' => 'Email pelamar kosong atau tidak valid']);
            return;
        }

        try {
            Mail::html($this->buildEmailHtml($recipientName, $message, $application), function ($mail) use ($recipientEmail, $recipientName, $subject) {
                $mail->to($recipientEmail, $recipientName)
                    ->subject($subject);
            });

            $log->update(['status' => 'sent', 'sent_at' => now()]);
        } catch (\Throwable $e) {
            Log::error('Email notification failed: ' . $e->getMessage());
            $log->update(['status' => 'failed', 'error' => $e->getMessage()]);
        }
    }

    /**
     * Send WhatsApp notification via Fonnte
     */
    public function sendWhatsApp(Application $application, string $type, string $message): void
    {
        $applicant = $application->applicant;
        $apiKey = Setting::get('fonnte_api_key', config('services.fonnte.key'));

        $log = NotificationLog::create([
            'application_id' => $application->id,
            'type' => $type,
            'channel' => 'whatsapp',
            'status' => 'pending',
            'message' => $message,
        ]);

        if (!$apiKey) {
            $log->update(['status' => 'failed', 'error' => 'Fonnte API key not configured']);
            return;
        }

        if (empty($applicant->whatsapp)) {
            $log->update(['status' => 'failed', 'error' => 'Nomor WhatsApp pelamar kosong']);
            return;
        }

        try {
            $response = Http::withHeaders([
                'Authorization' => $apiKey,
            ])->post('https://api.fonnte.com/send', [
                'target' => $applicant->whatsapp,
                'message' => strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $message)),
                'countryCode' => '62',
            ]);

            if ($response->successful() && $response->json('status')) {
                $log->update(['status' => 'sent', 'sent_at' => now()]);
            } else {
                $log->update(['status' => 'failed', 'error' => $response->body()]);
            }
        } catch (\Throwable $e) {
            Log::error('WhatsApp notification failed: ' . $e->getMessage());
            $log->update(['status' => 'failed', 'error' => $e->getMessage()]);
        }
    }

    /**
     * Resolve email recipient from primary and fallback sources.
     */
    private function resolveEmailRecipient(?string $primary, ?string $fallback): ?string
    {
        foreach ([$primary, $fallback] as $candidate) {
            $email = trim((string) $candidate);
            if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL)) {
                return $email;
            }
        }

        return null;
    }

    /**
     * Resolve display name for message recipient.
     */
    private function resolveRecipientName(?string $primary, ?string $fallback): string
    {
        $name = trim((string) ($primary ?: $fallback ?: 'Pelamar'));
        return $name !== '' ? $name : 'Pelamar';
    }

    /**
     * Build email HTML template
     */
    private function buildEmailHtml(string $name, string $message, Application $application): string
    {
        $siteName = e(Setting::get('site_name', 'Bursa Kerja'));
        $jobTitle = e($application->jobListing->title ?? 'Lowongan Pekerjaan');
        $safeName = e($name);

        return <<<HTML
        <!DOCTYPE html>
        <html>
        <head><meta charset="utf-8"></head>
        <body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; background: #f5f5f5;">
            <div style="background: white; border-radius: 10px; padding: 30px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
                <div style="text-align: center; margin-bottom: 20px;">
                    <h2 style="color: #4F46E5; margin: 0;">{$siteName}</h2>
                </div>
                <hr style="border: none; border-top: 2px solid #E5E7EB; margin: 20px 0;">
                <p>Halo <strong>{$safeName}</strong>,</p>
                <p>Posisi: <strong>{$jobTitle}</strong></p>
                <div style="background: #F9FAFB; border-radius: 8px; padding: 15px; margin: 15px 0;">
                    {$message}
                </div>
                <hr style="border: none; border-top: 1px solid #E5E7EB; margin: 20px 0;">
                <p style="color: #6B7280; font-size: 12px; text-align: center;">
                    Email ini dikirim secara otomatis oleh {$siteName}. Mohon tidak membalas email ini.
                </p>
            </div>
        </body>
        </html>
        HTML;
    }

    /**
     * Get notification message for a given type/status change
     * Uses customizable templates from DB, with hardcoded fallback
     */
    public function getMessageForStatus(string $newStatus, Application $application): array
    {
        $applicant = $application->applicant;
        $job = $application->jobListing;
        $siteName = Setting::get('site_name', 'Bursa Kerja');
        $siteUrl = config('app.url');

        // Base variables available to all templates
        $variables = [
            'applicant_name' => $applicant->name,
            'job_title' => $job->title,
            'company' => $job->company,
            'site_name' => $siteName,
            'site_url' => $siteUrl,
        ];

        // Determine template type and extra variables
        $templateType = null;
        $notificationType = $newStatus;
        $stageNum = null;
        $stageName = null;

        if ($newStatus === 'applied') {
            $templateType = 'applied';
            $notificationType = 'application_received';
        } elseif ($newStatus === 'accepted') {
            $templateType = 'accepted';
        } elseif ($newStatus === 'rejected') {
            $templateType = 'rejected';
        } elseif (preg_match('/^stage(\d+)_passed$/', $newStatus, $m)) {
            $templateType = 'stage_passed';
            $stageNum = (int) $m[1];
            $stage = $job->stages()->where('stage_number', $stageNum)->first();
            $stageName = $stage->name ?? "Tahap {$stageNum}";
            $variables['stage_name'] = $stageName;
            $variables['stage_number'] = $stageNum;
            $notificationType = "stage{$stageNum}_passed";
        } elseif (preg_match('/^stage(\d+)_form_filled$/', $newStatus, $m)) {
            $templateType = 'stage_form_filled';
            $stageNum = (int) $m[1];
            $stage = $job->stages()->where('stage_number', $stageNum)->first();
            $stageName = $stage->name ?? "Tahap {$stageNum}";
            $variables['stage_name'] = $stageName;
            $variables['stage_number'] = $stageNum;
            $notificationType = "stage{$stageNum}_form_filled";
        }

        // Try to load template from DB
        $template = $templateType ? MessageTemplate::getByType($templateType) : null;

        if ($template) {
            $subject = MessageTemplate::render($template->email_subject, $variables);
            $emailBody = MessageTemplate::render($template->email_body, $variables);
            $waBody = MessageTemplate::render($template->wa_body, $variables);

            return [
                'type' => $notificationType,
                'subject' => $subject,
                'message' => $emailBody,
                'wa_message' => $waBody,
            ];
        }

        // Fallback to hardcoded defaults if template not found in DB
        return $this->getHardcodedMessage($newStatus, $application, $variables, $siteName, $siteUrl);
    }

    /**
     * Hardcoded fallback messages (used when no DB template exists)
     */
    private function getHardcodedMessage(string $newStatus, Application $application, array $vars, string $siteName, string $siteUrl): array
    {
        $job = $application->jobListing;

        if ($newStatus === 'applied') {
            return [
                'type' => 'application_received',
                'subject' => "Lamaran Diterima - {$job->title}",
                'message' => "Lamaran Anda untuk posisi <strong>{$job->title}</strong> di <strong>{$job->company}</strong> telah kami terima.<br><br>Kami akan meninjau lamaran Anda dan menghubungi Anda kembali.<br><br>Terima kasih telah melamar melalui {$siteName}.",
                'wa_message' => "Halo {$vars['applicant_name']},\n\nLamaran Anda untuk posisi *{$job->title}* di *{$job->company}* telah kami terima.\n\nKami akan meninjau lamaran Anda dan menghubungi Anda kembali.\n\nTerima kasih telah melamar melalui {$siteName}.",
            ];
        }

        if ($newStatus === 'accepted') {
            return [
                'type' => 'accepted',
                'subject' => "Selamat! Anda DITERIMA - {$job->title}",
                'message' => "Selamat! Anda dinyatakan <strong>DITERIMA</strong> untuk posisi <strong>{$job->title}</strong> di <strong>{$job->company}</strong>!<br><br>Silakan cek dashboard Anda untuk informasi lebih lanjut:<br><a href='{$siteUrl}/dashboard'>{$siteUrl}/dashboard</a><br><br>Terima kasih atas partisipasi Anda.",
                'wa_message' => "Halo {$vars['applicant_name']},\n\nSelamat! Anda dinyatakan *DITERIMA* untuk posisi *{$job->title}* di *{$job->company}*!\n\nSilakan cek dashboard Anda: {$siteUrl}/dashboard\n\nTerima kasih atas partisipasi Anda.",
            ];
        }

        if ($newStatus === 'rejected') {
            return [
                'type' => 'rejected',
                'subject' => "Hasil Seleksi - {$job->title}",
                'message' => "Terima kasih telah mengikuti proses seleksi untuk posisi <strong>{$job->title}</strong> di <strong>{$job->company}</strong>.<br><br>Dengan berat hati kami informasikan bahwa Anda <strong>belum berhasil lolos</strong> pada seleksi kali ini.<br><br>Jangan berkecil hati! Anda masih bisa melamar posisi lainnya di:<br><a href='{$siteUrl}'>{$siteUrl}</a>",
                'wa_message' => "Halo {$vars['applicant_name']},\n\nTerima kasih telah mengikuti proses seleksi untuk posisi *{$job->title}* di *{$job->company}*.\n\nDengan berat hati kami informasikan bahwa Anda belum berhasil lolos pada seleksi kali ini.\n\nJangan berkecil hati! Anda masih bisa melamar posisi lainnya di: {$siteUrl}",
            ];
        }

        if (preg_match('/^stage(\d+)_passed$/', $newStatus, $m)) {
            $stageNum = (int) $m[1];
            $stageName = $vars['stage_name'] ?? "Tahap {$stageNum}";
            return [
                'type' => "stage{$stageNum}_passed",
                'subject' => "Selamat! Lolos {$stageName} - {$job->title}",
                'message' => "Selamat! Anda dinyatakan <strong>LOLOS {$stageName}</strong> untuk posisi <strong>{$job->title}</strong> di <strong>{$job->company}</strong>.<br><br>Silakan akses dashboard Anda: <a href='{$siteUrl}/dashboard'>{$siteUrl}/dashboard</a>",
                'wa_message' => "Halo {$vars['applicant_name']},\n\nSelamat! Anda dinyatakan *LOLOS {$stageName}* untuk posisi *{$job->title}* di *{$job->company}*.\n\nSilakan akses dashboard Anda: {$siteUrl}/dashboard",
            ];
        }

        if (preg_match('/^stage(\d+)_form_filled$/', $newStatus, $m)) {
            $stageNum = (int) $m[1];
            $stageName = $vars['stage_name'] ?? "Tahap {$stageNum}";
            return [
                'type' => "stage{$stageNum}_form_filled",
                'subject' => "Formulir {$stageName} Diterima - {$job->title}",
                'message' => "Formulir <strong>{$stageName}</strong> Anda untuk posisi <strong>{$job->title}</strong> telah kami terima.<br><br>Kami akan meninjau data Anda dan menghubungi kembali.",
                'wa_message' => "Halo {$vars['applicant_name']},\n\nFormulir *{$stageName}* Anda untuk posisi *{$job->title}* telah kami terima.\n\nKami akan meninjau data Anda dan menghubungi kembali.",
            ];
        }

        return [
            'type' => $newStatus,
            'subject' => "Notifikasi - {$siteName}",
            'message' => "Ada pembaruan terkait lamaran Anda untuk posisi <strong>{$job->title}</strong> di {$siteName}.",
            'wa_message' => "Halo {$vars['applicant_name']},\n\nAda pembaruan terkait lamaran Anda untuk posisi *{$job->title}* di {$siteName}.",
        ];
    }

    /**
     * Auto-send notification when status changes (immediate - for applicant actions & auto-advance)
     * This is the main entry point called from applicant controllers & auto-advance command
     */
    public function notifyStatusChange(Application $application, string $newStatus): void
    {
        $msg = $this->getMessageForStatus($newStatus, $application);
        $this->send($application, $msg['type'], $msg['subject'], $msg['message'], $msg['wa_message'] ?? null);
    }

    /**
     * Schedule notification when admin changes status manually
     * Notifications will be queued and sent based on the configured schedule
     * Returns the scheduled notification logs
     */
    public function scheduleStatusChange(Application $application, string $newStatus, ?\DateTimeInterface $scheduledAt = null): array
    {
        $msg = $this->getMessageForStatus($newStatus, $application);
        return $this->schedule($application, $msg['type'], $msg['subject'], $msg['message'], $msg['wa_message'] ?? null, $scheduledAt);
    }

    /**
     * Schedule only the NEXT stage notification for an application.
     * Called after apply (schedules stage1_passed) or after form submit (schedules stageN+1_passed).
     * Timing: interval days from NOW (current moment).
     *
     * Flow:
     *   applied            -> schedule stage1_passed (H+interval from apply)
     *   stageN_form_filled -> schedule stage(N+1)_passed (H+interval from form submit)
     *   last stage filled  -> schedule final decision (H+interval from form submit)
     */
    public function scheduleNextStageNotification(Application $application): void
    {
        $job = $application->jobListing;
        if (!$job) return;

        $stages = $job->stages()->where('is_active', true)->orderBy('stage_number')->get();
        $totalStages = $stages->count();
        if ($totalStages === 0) return;

        $intervalDays = (int) Setting::get('stage_advance_days', 2);
        $scheduledAt = now()->addDays($intervalDays);

        $currentStatus = $application->status;
        $nextStatus = null;

        if ($currentStatus === 'applied') {
            // After applying: schedule first stage
            $nextStatus = 'stage' . $stages->first()->stage_number . '_passed';
        } elseif (preg_match('/^stage(\d+)_form_filled$/', $currentStatus, $m)) {
            // After filling a form: schedule next stage or auto-reject
            $currentStageNum = (int) $m[1];
            $nextStage = $stages->first(fn($s) => $s->stage_number > $currentStageNum);
            if ($nextStage) {
                $nextStatus = 'stage' . $nextStage->stage_number . '_passed';
            } else {
                // All stages done → schedule final decision based on setting
                $nextStatus = Setting::get('final_auto_decision', 'rejected');
            }
        }

        if (!$nextStatus) return;

        // Avoid duplicates
        $exists = NotificationLog::where('application_id', $application->id)
            ->where('type', $nextStatus)
            ->whereIn('status', ['scheduled', 'sent'])
            ->exists();

        if (!$exists) {
            $this->scheduleStatusChange($application, $nextStatus, $scheduledAt);
        }
    }

    /**
     * Auto-advance application status when a scheduled stage notification is sent.
     * Called by ProcessScheduledNotifications after successfully sending.
     */
    public function advanceStatusForNotification(NotificationLog $log): void
    {
        $application = $log->application;
        if (!$application) return;

        $type = $log->type;

        // Only advance for stage_passed notifications or final decisions
        if (preg_match('/^stage(\d+)_passed$/', $type, $m)) {
            $stageNum = (int) $m[1];
            $expectedPrior = ['stage' . ($stageNum - 1) . '_form_filled'];
            // 'applied' is only a valid prior status for stage 1
            if ($stageNum === 1) {
                $expectedPrior[] = 'applied';
            }
            // Also allow advancing from previous stage_passed if user didn't fill form
            if ($stageNum > 1) {
                $expectedPrior[] = 'stage' . ($stageNum - 1) . '_passed';
            }

            // Only advance if application is at the expected prior status
            if (in_array($application->status, $expectedPrior)) {
                $application->update([
                    'status' => $type,
                    'current_stage' => $stageNum,
                ]);
                Log::info("Auto-advanced application {$application->id} to {$type}");
            }
        } elseif ($type === 'accepted' || $type === 'rejected') {
            // Final decision
            if (!in_array($application->status, ['accepted', 'rejected'])) {
                $application->update([
                    'status' => $type,
                    'final_decision_at' => now(),
                ]);
                Log::info("Auto-advanced application {$application->id} to final: {$type}");
            }
        }
    }

    /**
     * Pre-schedule all stage_passed + final decision notifications for an application.
     *
     * @deprecated Use scheduleNextStageNotification() instead.
     * This method is kept for backward compatibility but now delegates
     * to scheduleNextStageNotification() to respect form-completion-based flow.
     */
    public function scheduleAllStageNotifications(Application $application): void
    {
        // Only schedule the next stage, not all at once
        $this->scheduleNextStageNotification($application);
    }

    /**
     * Re-sync all scheduled stage notifications for a job.
     * Called when admin edits/toggles stages.
     * Cancels all outdated scheduled stage notifications and re-schedules
     * only the NEXT pending notification based on each application's current state.
     *
     * New logic: only schedule the next step, not all at once.
     * Interval is calculated from the relevant reference time (form submit or apply).
     */
    public function resyncNotificationsForJob(JobListing $job): int
    {
        $applications = Application::where('job_listing_id', $job->id)
            ->whereNotIn('status', ['accepted', 'rejected'])
            ->with(['applicant', 'stageResponses'])
            ->get();

        if ($applications->isEmpty()) return 0;

        $synced = 0;

        foreach ($applications as $application) {
            // Cancel all currently scheduled stage_passed, rejected, and accepted notifications
            NotificationLog::where('application_id', $application->id)
                ->where('status', 'scheduled')
                ->where(function ($q) {
                    $q->where('type', 'like', 'stage%_passed')
                      ->orWhere('type', 'rejected')
                      ->orWhere('type', 'accepted');
                })
                ->update(['status' => 'cancelled']);

            // Re-schedule only the next notification based on current status
            $this->scheduleNextStageNotification($application);

            $synced++;
        }

        return $synced;
    }

    /**
     * Legacy notify method for backward compatibility
     */
    public function notify(Application $application, string $type): void
    {
        $this->notifyStatusChange($application, match ($type) {
            'application_received' => 'applied',
            'stage1_passed' => 'stage1_passed',
            'stage2_submitted' => 'stage2_form_filled',
            'stage2_passed' => 'stage2_passed',
            'stage3_submitted' => 'stage3_form_filled',
            default => $type,
        });
    }
}
