<?php

namespace App\Domains\Integration\Services;

use App\Domains\Client\Models\Client;
use App\Domains\Tenant\Models\Tenant;
use App\Domains\Tenant\Models\WebsiteType;
use Exception;
use Illuminate\Contracts\Mail\Factory as MailFactory;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\MailManager;
use Illuminate\Support\Facades\Blade;
use InvalidArgumentException;

class MailService extends BaseIntegrationService
{
    private const REQUIRED_SMTP_FIELDS = [
        'MAIL_HOST',
        'MAIL_PORT',
        'MAIL_USERNAME',
        'MAIL_PASSWORD',
        'MAIL_FROM_ADDRESS',
    ];

    protected string $integrationCode = 'email';

    private readonly MailFactory $mailFactory;

    private ?Mailer $mailer = null;

    private bool $usesClientMailer = false;

    public function __construct(?MailFactory $mailFactory = null)
    {
        $this->mailFactory = $mailFactory ?? app(MailFactory::class);
    }

    public function forTenant(string $tenantCode): self
    {
        parent::forTenant($tenantCode);

        if ($this->clientIntegration) {
            $this->mailer = $this->resolveMailer();
            $this->usesClientMailer = true;
        } else {
            $this->mailer = $this->mailFactory->mailer();
            $this->usesClientMailer = false;
        }

        return $this;
    }

    public function forClient(Client|string $client): self
    {
        parent::forClient($client);
        $this->tenant = $this->clientContext?->tenants()->first();

        if ($this->clientIntegration) {
            $this->mailer = $this->resolveMailer();
            $this->usesClientMailer = true;
        } else {
            $this->mailer = $this->mailFactory->mailer();
            $this->usesClientMailer = false;
        }

        return $this;
    }

    public function getHeaders(): array
    {
        return [];
    }

    /**
     * @param  array<int, array{data: string, name: string, mime: string}>  $attachments
     */
    public function send(
        string|array $recipient,
        string $subject,
        string $content,
        Tenant|WebsiteType|null $brand = null,
        array $attachments = [],
    ): void {
        if (! $this->mailer || ! $this->tenant) {
            throw new Exception('MailService no está configurado. Llamá a forTenant() o forClient() primero.');
        }

        $brand ??= $this->tenant;
        $branding = $this->brandingFor($brand);

        $html = Blade::render(
            <<<'BLADE'
                <x-mail.branded-layout :branding="$branding" :header-logo-url="$headerLogoUrl" :footer-logo-url="$footerLogoUrl">
                    {!! $content !!}
                </x-mail.branded-layout>
                BLADE,
            [
                'branding' => $branding,
                'headerLogoUrl' => $brand instanceof WebsiteType
                    ? $brand->siteLogo?->getTemporaryUrl(1440)
                    : $brand->headerLogo?->getTemporaryUrl(1440),
                'footerLogoUrl' => $brand->footerLogo?->getTemporaryUrl(1440),
                'content' => $content,
            ],
        );

        $mail = (new Mailable)
            ->subject($subject)
            ->html($html);

        foreach ($attachments as $attachment) {
            $mail->attachData(
                $attachment['data'],
                $attachment['name'],
                ['mime' => $attachment['mime']],
            );
        }

        $this->mailer->to($recipient)->send($mail);
    }

    public function mailerName(): string
    {
        return $this->usesClientMailer
            ? 'client-smtp'
            : (string) config('mail.default');
    }

    /** @return array{name: string, primary_color: string, body_color: string, background_color: string, surface_color: string, header_bg_color: string, footer_bg_color: string} */
    private function brandingFor(Tenant|WebsiteType $brand): array
    {
        if ($brand instanceof WebsiteType) {
            $brand->loadMissing(['siteLogo', 'footerLogo']);

            return [
                'name' => $brand->nombre,
                'primary_color' => $brand->primary_color ?? '#FF7006',
                'body_color' => $brand->body_color ?? '#666666',
                'background_color' => $brand->background_color ?? '#f8f8f8',
                'surface_color' => $brand->surface_color ?? '#ffffff',
                'header_bg_color' => $brand->surface_color ?? '#ffffff',
                'footer_bg_color' => $brand->login_header_footer_color ?? '#838383',
            ];
        }

        $brand->loadMissing(['headerLogo', 'footerLogo']);

        return [
            'name' => $brand->nombre,
            'primary_color' => $brand->primary_color ?? '#6376f3',
            'body_color' => '#334155',
            'background_color' => '#f1f5f9',
            'surface_color' => '#ffffff',
            'header_bg_color' => $brand->header_bg_color ?? '#ffffff',
            'footer_bg_color' => $brand->footer_bg_color ?? '#334155',
        ];
    }

    public function onSetup(): void
    {
        if (! $this->mailer || ! $this->clientContext) {
            throw new Exception('MailService no está configurado. Llamá a forTenant() o forClient() primero.');
        }

        $recipient = $this->getIntegrationSetting('MAIL_FROM_ADDRESS');

        if (! is_string($recipient) || $recipient === '') {
            throw new InvalidArgumentException('Falta MAIL_FROM_ADDRESS en la configuración SMTP del cliente.');
        }

        $subject = 'Configuración de correo validada';
        $content = '<h1 style="margin: 0 0 20px;">Configuración de correo validada</h1>'
            .'<p>La integración SMTP de '.e($this->clientContext->name).' fue configurada correctamente.</p>'
            .'<p style="color: #64748b; font-size: 13px;">Este mensaje fue enviado automáticamente para validar las credenciales de correo.</p>';

        if ($this->tenant) {
            $this->send($recipient, $subject, $content);

            return;
        }

        $this->mailer->to($recipient)->send(
            (new Mailable)->subject($subject)->html($content)
        );
    }

    private function resolveMailer(): Mailer
    {
        $data = $this->clientIntegration?->integration_data;

        if (! is_array($data)) {
            throw new InvalidArgumentException('La configuración SMTP del cliente no es válida.');
        }

        foreach (self::REQUIRED_SMTP_FIELDS as $field) {
            if (! array_key_exists($field, $data) || $data[$field] === null || $data[$field] === '') {
                throw new InvalidArgumentException("Falta {$field} en la configuración SMTP del cliente.");
            }
        }

        // MailFake implements MailFactory but cannot build transports.
        if (! $this->mailFactory instanceof MailManager) {
            return $this->mailFactory->mailer();
        }

        $mailer = $this->mailFactory->build([
            'name' => 'client-smtp-'.$this->clientContext?->id,
            'transport' => 'smtp',
            'scheme' => $data['MAIL_SCHEME'] ?? null,
            'host' => $data['MAIL_HOST'],
            'port' => (int) $data['MAIL_PORT'],
            'username' => $data['MAIL_USERNAME'],
            'password' => $data['MAIL_PASSWORD'],
            'timeout' => isset($data['MAIL_TIMEOUT']) ? (int) $data['MAIL_TIMEOUT'] : null,
            'local_domain' => $data['MAIL_EHLO_DOMAIN'] ?? null,
        ]);

        $mailer->alwaysFrom(
            $data['MAIL_FROM_ADDRESS'],
            $data['MAIL_FROM_NAME'] ?? $this->clientContext?->name,
        );

        return $mailer;
    }
}
