<?php

namespace App\Services\Mail;

use App\Models\AgencyManagementReport;
use App\Models\EmailLog;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;
use RuntimeException;
use Throwable;

class AgencyManagementReportMailer
{
    public function __construct(
        private readonly MailSettingsManager $mailSettings,
        private readonly AgencyManagementMailSettingsManager $managementSettings,
    ) {
    }

    /**
     * @param array<string, mixed> $options
     */
    public function send(AgencyManagementReport $report, array $options = []): EmailLog
    {
        if ($report->status !== 'completed') {
            throw new RuntimeException('Tamamlanmamış ajans yönetim raporu gönderilemez. Önce raporu yeniden oluşturun.');
        }

        $settings = $this->managementSettings->all();
        $recipients = $this->normalizeEmails(Arr::get($options, 'recipients', $settings['recipients'] ?? ''));
        $cc = $this->normalizeEmails(Arr::get($options, 'cc', $settings['cc'] ?? ''));
        $bcc = $this->normalizeEmails(Arr::get($options, 'bcc', $settings['bcc'] ?? ''));

        if ($recipients === []) {
            throw new RuntimeException('Ajans yönetim raporu için en az bir yönetici alıcısı gerekir.');
        }

        $subject = $this->subject($report, Arr::get($options, 'subject_prefix', $settings['subject_prefix'] ?? null));
        $attachments = $this->attachments($report, [
            'include_html' => Arr::get($options, 'include_html', $settings['include_html'] ?? true),
            'include_csv' => Arr::get($options, 'include_csv', $settings['include_csv'] ?? true),
        ]);

        $emailLog = EmailLog::create([
            'client_id' => null,
            'generated_report_id' => null,
            'subject' => $subject,
            'recipients' => $recipients,
            'cc' => $cc,
            'bcc' => $bcc,
            'status' => 'queued',
            'attachment_paths' => array_values($attachments),
            'meta' => [
                'type' => 'agency_management_report',
                'agency_management_report_id' => $report->id,
                'period_type' => $report->period_type,
                'date_from' => optional($report->date_from)->toDateString(),
                'date_to' => optional($report->date_to)->toDateString(),
            ],
        ]);

        try {
            $this->mailSettings->apply();
            $smtpSettings = $this->mailSettings->all();
            $note = Arr::get($options, 'note', $settings['intro_note'] ?? null);

            Mail::send('emails.management.report-ready', [
                'report' => $report,
                'note' => $note,
                'downloadHtmlUrl' => $report->htmlExists() ? route('admin.management-reports.download', [$report, 'html']) : null,
                'downloadCsvUrl' => $report->csvExists() ? route('admin.management-reports.download', [$report, 'csv']) : null,
            ], function ($message) use ($subject, $recipients, $cc, $bcc, $attachments, $smtpSettings) {
                $message->to($recipients)->subject($subject);

                if ($cc !== []) {
                    $message->cc($cc);
                }

                if ($bcc !== []) {
                    $message->bcc($bcc);
                }

                if (filled($smtpSettings['from_email'] ?? null)) {
                    $message->from($smtpSettings['from_email'], $smtpSettings['from_name'] ?? null);
                }

                if (filled($smtpSettings['reply_to'] ?? null)) {
                    $message->replyTo($smtpSettings['reply_to']);
                }

                foreach ($attachments as $relativePath) {
                    if (Storage::disk('public')->exists($relativePath)) {
                        $message->attach(Storage::disk('public')->path($relativePath), [
                            'as' => basename($relativePath),
                            'mime' => $this->mimeFor($relativePath),
                        ]);
                    }
                }
            });

            $emailLog->update([
                'status' => 'sent',
                'sent_at' => now(),
                'error_message' => null,
            ]);
        } catch (Throwable $exception) {
            report($exception);

            $emailLog->update([
                'status' => 'failed',
                'error_message' => $exception->getMessage(),
            ]);
        }

        return $emailLog->refresh();
    }

    /**
     * @param string|array<int, string>|null $value
     * @return array<int, string>
     */
    public function normalizeEmails(string|array|null $value): array
    {
        if (is_array($value)) {
            $items = $value;
        } else {
            $items = preg_split('/\r\n|\r|\n|,|;/', (string) $value) ?: [];
        }

        return collect($items)
            ->map(fn ($email) => trim((string) $email))
            ->filter(fn ($email) => filter_var($email, FILTER_VALIDATE_EMAIL))
            ->unique()
            ->values()
            ->all();
    }

    private function subject(AgencyManagementReport $report, ?string $prefix = null): string
    {
        $prefix = trim((string) ($prefix ?: 'DW Ads Reporter'));
        $range = optional($report->date_from)->format('d.m.Y').' - '.optional($report->date_to)->format('d.m.Y');

        return $prefix.' · '.$report->periodLabel().' Ajans Yönetim Raporu · '.$range;
    }

    /**
     * @param array<string, mixed> $options
     * @return array<string, string>
     */
    private function attachments(AgencyManagementReport $report, array $options): array
    {
        $attachments = [];

        if ((bool) Arr::get($options, 'include_html', true) && $report->html_path && Storage::disk('public')->exists($report->html_path)) {
            $attachments['html'] = $report->html_path;
        }

        if ((bool) Arr::get($options, 'include_csv', true) && $report->csv_path && Storage::disk('public')->exists($report->csv_path)) {
            $attachments['csv'] = $report->csv_path;
        }

        return $attachments;
    }

    private function mimeFor(string $path): string
    {
        return match (pathinfo($path, PATHINFO_EXTENSION)) {
            'csv' => 'text/csv',
            'html' => 'text/html',
            default => 'application/octet-stream',
        };
    }
}
