<?php

namespace App\Services\Payments;

use App\Models\Configuration;
use App\Models\FamilyGuardian;
use App\Models\Invoice;
use App\Models\PaymentNotificationLog;
use App\Models\User;
use App\Services\EmailService;
use DateTimeImmutable;
use DateTimeZone;

class PaymentTestNotificationService
{
    public function __construct(private EmailService $emailService)
    {
    }

    public function send(string $email, string $type = 'no_payment'): array
    {
        $email = trim($email);
        if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return ['ok' => false, 'message' => 'Invalid email address.'];
        }

        $type = in_array($type, ['no_payment', 'installment'], true) ? $type : 'no_payment';

        $tzName = $this->resolveTimezone();
        $tz = new DateTimeZone($tzName);
        $now = new DateTimeImmutable('now', $tz);

        $year = (int) $now->format('Y');
        $month = (int) $now->format('n');
        $schoolYear = (string) (Configuration::getConfig('school_year') ?? $year);

        $user = User::query()->where('email', $email)->first();
        $parentId = (int) ($user->id ?? 0);

        $invoices = $parentId > 0
            ? Invoice::query()->where('parent_id', $parentId)->where('school_year', $schoolYear)->get()
            : collect();

        $totalBalance = 0.0;
        $latestInvoiceId = null;
        foreach ($invoices as $invoice) {
            $totalBalance += (float) ($invoice->balance ?? 0);
            if ($latestInvoiceId === null) {
                $latestInvoiceId = (int) ($invoice->id ?? 0);
            }
        }

        $ccEmail = $this->findSecondaryGuardianEmail($parentId, $email);

        $parentName = $user ? trim(($user->firstname ?? '') . ' ' . ($user->lastname ?? '')) : '';
        $monthYear = $now->format('F Y');
        $subject = sprintf('Monthly Tuition Reminder — %s', $schoolYear);
        $greeting = $parentName !== '' ? "Dear {$parentName}," : 'Dear Parent,';
        $balanceFmt = '$' . number_format($totalBalance, 2);
        $intro = ($type === 'no_payment')
            ? "We noticed there are outstanding tuition charges for {$schoolYear} but no payment has been recorded yet."
            : "This is your monthly installment reminder for {$schoolYear}.";

        $installmentInfo = $this->computeInstallmentSuggestion($totalBalance, $tzName);

        $bodyHtml = <<<HTML
            <div style="font-family:Arial,Helvetica,sans-serif; font-size:14px; color:#212529; line-height:1.5;">
              <h2 style="margin:0 0 10px; font-size:18px;">Monthly Tuition Reminder (Test)</h2>
              <p>{$greeting}</p>
              <p>{$intro}</p>
              <p><strong>Current Outstanding Balance:</strong> {$balanceFmt}</p>
              <p>
                As a friendly reminder, our tuition installments are due at the beginning of each month.
                You can review your invoice and payment options by logging in to your parent portal.
              </p>
              <p>Thank you for your prompt attention.</p>
              <p><em>Reminder Period:</em> {$monthYear}</p>
            </div>
        HTML;

        $bodyHtml .= "<ul>"
            . "<li><strong>Remaining installments:</strong> {$installmentInfo['remaining_installments']}</li>"
            . "<li><strong>Suggested installment this month:</strong> {$installmentInfo['installment_due_fmt']}</li>"
            . "<li><strong>Maximum installments available:</strong> {$installmentInfo['max_installments']}</li>"
            . "</ul>";

        if (view()->exists('emails._wrap_layout')) {
            $body = view('emails._wrap_layout', [
                'title' => 'Monthly Tuition Reminder',
                'body_html' => $bodyHtml,
            ], ['saveData' => true]);
        } else {
            $body = $bodyHtml;
        }

        $ok = $this->emailService->send($email, $subject, (string) $body, 'finance');
        if ($ok && $ccEmail && strcasecmp($ccEmail, $email) !== 0) {
            $this->emailService->send($ccEmail, $subject, (string) $body, 'finance');
        }

        $existing = PaymentNotificationLog::query()
            ->where('parent_id', $parentId)
            ->where('period_year', $year)
            ->where('period_month', $month)
            ->where('type', $type)
            ->first();

        $payload = [
            'parent_id' => $parentId,
            'invoice_id' => $latestInvoiceId,
            'school_year' => $schoolYear,
            'period_year' => $year,
            'period_month' => $month,
            'type' => $type,
            'to_email' => $email,
            'cc_email' => $ccEmail,
            'head_fa_notified' => 0,
            'subject' => $subject,
            'body' => (string) $body,
            'status' => $ok ? 'sent' : 'failed',
            'error_message' => $ok ? null : 'Email send failed (see logs)',
            'balance_snapshot' => $totalBalance,
            'sent_at' => $now->format('Y-m-d H:i:s'),
        ];

        if ($existing) {
            $existing->fill($payload)->save();
            $logId = (int) $existing->id;
        } else {
            $log = PaymentNotificationLog::query()->create($payload);
            $logId = (int) $log->id;
        }

        return [
            'ok' => $ok,
            'log_id' => $logId,
            'cc_email' => $ccEmail,
        ];
    }

    private function computeInstallmentSuggestion(float $balance, string $tzName): array
    {
        $installmentEndRaw = (string) (Configuration::getConfig('installment_date') ?? '');
        $tz = new DateTimeZone($tzName);
        $today = new DateTimeImmutable('today', $tz);

        $end = null;
        if ($installmentEndRaw !== '') {
            try {
                $end = new DateTimeImmutable($installmentEndRaw, $tz);
            } catch (\Throwable $e) {
                $end = null;
            }
        }

        $remMonths = 0;
        if ($end) {
            $y = (int) $end->format('Y') - (int) $today->format('Y');
            $m = (int) $end->format('n') - (int) $today->format('n');
            $remMonths = $y * 12 + $m;
            if ((int) $end->format('j') > (int) $today->format('j')) {
                $remMonths += 1;
            }
            if ($remMonths < 0) {
                $remMonths = 0;
            }
        }

        $remainingInstallments = max(1, $remMonths);
        $maxInstallments = max($remMonths ?: 0, $balance > 0 ? 2 : 0);
        $installmentDue = $remainingInstallments > 0 ? ($balance / $remainingInstallments) : 0;

        return [
            'remaining_installments' => $remainingInstallments,
            'max_installments' => $maxInstallments,
            'installment_due' => round($installmentDue, 2),
            'installment_due_fmt' => '$' . number_format($installmentDue, 2),
        ];
    }

    private function findSecondaryGuardianEmail(int $parentId, string $primaryEmail): ?string
    {
        if ($parentId <= 0) {
            return null;
        }

        $row = FamilyGuardian::query()->where('user_id', $parentId)->first();
        if (!$row || empty($row->family_id)) {
            return null;
        }

        $others = FamilyGuardian::query()
            ->where('family_id', (int) $row->family_id)
            ->where('user_id', '!=', $parentId)
            ->where('receive_emails', 1)
            ->get();

        foreach ($others as $guardian) {
            $email = (string) (User::query()->where('id', (int) $guardian->user_id)->value('email') ?? '');
            if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL) && strcasecmp($email, $primaryEmail) !== 0) {
                return $email;
            }
        }

        return null;
    }

    private function resolveTimezone(): string
    {
        $schoolConfig = config('School');
        if (is_object($schoolConfig) && isset($schoolConfig->attendance['timezone'])) {
            return (string) $schoolConfig->attendance['timezone'];
        }
        if (is_array($schoolConfig) && isset($schoolConfig['attendance']['timezone'])) {
            return (string) $schoolConfig['attendance']['timezone'];
        }

        return (string) (config('app.timezone') ?: 'UTC');
    }
}
