<?php

namespace App\Mail\Subscription;

use App\Models\Subscription;
use App\Services\Settings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

/**
 * Shared base for every subscription lifecycle mailable. Queueable so
 * webhook handlers don't block on SMTP (database queue per Hostinger
 * constraint — see CLAUDE.md). Concrete subclasses set the subject in
 * envelope() and the Markdown view in content().
 *
 * commonData() resolves branding (site name + logo URL + support email)
 * from Settings + the existing branding pipeline so emails match the
 * marketing chrome admin already customized. User-facing fields fall
 * back gracefully: `userName` to "there", `planName` to "your plan",
 * etc., so a half-populated subscription (test data, partial provider
 * state) doesn't blow up the render.
 */
abstract class BaseSubscriptionMail extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;

    public function __construct(
        public Subscription $subscription,
    ) {}

    /** Shared template data — branding + commonly-needed fields.
     *  Subclasses can `array_merge` extra keys into this. */
    protected function commonData(): array
    {
        $siteName = self::settingString('site.name', config('app.name', 'AppShot AI'));
        $logoPath = self::settingString('branding.logo', '');
        $supportEmail = self::settingString('site.support_email', config('mail.from.address', ''));

        $logoUrl = null;
        if ($logoPath !== '') {
            try {
                $logoUrl = \App\Services\MediaStorage::url($logoPath);
            } catch (\Throwable) {
                $logoUrl = null;
            }
        }

        $user = $this->subscription->user;
        $plan = $this->subscription->plan;
        $currency = $this->subscription->currency;

        return [
            'siteName' => $siteName,
            'logoUrl' => $logoUrl,
            'supportEmail' => $supportEmail,
            'userName' => $user?->name ?: 'there',
            'planName' => $plan?->name ?: 'your plan',
            'currencyCode' => $currency?->code ?: 'USD',
            'periodLabel' => $this->subscription->period === 'yearly' ? 'year' : 'month',
            'accountUrl' => self::safeRoute('account.subscription'),
            'pricingUrl' => self::safeRoute('pricing'),
            'subscription' => $this->subscription,
        ];
    }

    /** Resolve a `Subscription`'s recipient email — prefers the active
     *  user; falls back to `user_email_snapshot` for accounting cases
     *  where the user was purged but the sub stays. Returns null when
     *  no resolvable address (don't send to ghosts). */
    public static function recipientEmail(Subscription $sub): ?string
    {
        $email = $sub->user?->email ?: $sub->user_email_snapshot;

        return is_string($email) && $email !== '' ? $email : null;
    }

    /** Format an integer minor-unit amount in the sub's currency
     *  (USD/INR/EUR/GBP all 100-base). */
    protected function formatAmount(int $minor): string
    {
        $currency = $this->subscription->currency;
        $symbol = $currency?->symbol ?: ($currency?->code ?: '');
        $major = number_format($minor / 100, 2);

        return $symbol === '' ? $major : "{$symbol}{$major}";
    }

    private static function settingString(string $key, string $default): string
    {
        try {
            $value = Settings::get($key, $default);

            return is_string($value) && $value !== '' ? $value : $default;
        } catch (\Throwable) {
            return $default;
        }
    }

    /** Safe `route()` wrapper — returns the APP_URL fallback when the
     *  route isn't defined (lets emails still render in test contexts). */
    private static function safeRoute(string $name): string
    {
        try {
            return route($name);
        } catch (\Throwable) {
            return rtrim((string) config('app.url'), '/');
        }
    }
}
