<?php

namespace App\Models;

use App\Models\Admin;
use App\Models\Bank;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Log;

class MailingBounce extends Model
{
    protected $table = 'mailing_bounces';

    protected $fillable = [
        'email',
        'bounce_type',
        'bounce_reason',
        'mailing_id',
        'bounced_at',
        'is_suppressed',
    ];

    protected $casts = [
        'bounced_at' => 'datetime',
        'is_suppressed' => 'boolean',
    ];

    public function mailing(): BelongsTo
    {
        return $this->belongsTo(Mailing::class);
    }

    /**
     * Check if an email address should be suppressed from sending
     */
    public static function isSuppressed(string $email): bool
    {
        return self::where('email', $email)
            ->where('is_suppressed', true)
            ->exists();
    }

    /**
     * Suppress an email address from future mailings
     */
    public static function suppressEmail(string $email, string $reason = null): void
    {
        self::updateOrCreate(
            ['email' => $email],
            [
                'bounce_reason' => $reason ?? 'Email suppressed',
                'bounced_at' => now(),
                'is_suppressed' => true,
                'bounce_type' => 'suppressed',
            ]
        );
    }

    /**
     * Record a bounce for an email with threshold-based actions
     */
    public static function recordBounce(
        string $email,
        string $bounceType = 'hard',
        string $reason = null,
        int $mailingId = null
    ): self {
        // Create the bounce record
        $bounce = self::create([
            'email' => $email,
            'bounce_type' => $bounceType,
            'bounce_reason' => $reason,
            'mailing_id' => $mailingId,
            'bounced_at' => now(),
            'is_suppressed' => false, // Don't auto-suppress, use threshold-based logic
        ]);

        // Check if this bounce should trigger threshold-based actions
        if (self::isDefinitiveHardBounce($bounceType, $reason)) {
            self::checkAndApplyThresholds($email, $reason);
        }

        return $bounce;
    }

    /**
     * Check bounce counts and apply threshold-based actions
     */
    protected static function checkAndApplyThresholds(string $email, string $reason): void
    {
        $config = timebank_config('mailing.bounce_thresholds', []);
        $suppressionThreshold = $config['suppression_threshold'] ?? 3;
        $verificationResetThreshold = $config['verification_reset_threshold'] ?? 2;
        $windowDays = $config['counting_window_days'] ?? 30;

        // Count recent definitive hard bounces for this email
        $recentBounceCount = self::countRecentDefinitiveBounces($email, $windowDays);

        Log::info("Email {$email} has {$recentBounceCount} recent hard bounces (suppression: {$suppressionThreshold}, verification reset: {$verificationResetThreshold})");

        // Check verification reset threshold first (lower threshold)
        if ($recentBounceCount >= $verificationResetThreshold && !self::hasVerificationBeenReset($email)) {
            self::resetEmailVerificationForAddress($email, $reason);
            self::markVerificationReset($email);
        }

        // Check suppression threshold
        if ($recentBounceCount >= $suppressionThreshold) {
            self::suppressEmailByThreshold($email, $reason, $recentBounceCount);
        }
    }

    /**
     * Count recent definitive hard bounces for an email address
     */
    protected static function countRecentDefinitiveBounces(string $email, int $windowDays): int
    {
        $config = timebank_config('mailing.bounce_thresholds', []);
        $countedTypes = $config['counted_bounce_types'] ?? ['hard'];
        $patterns = $config['definitive_hard_bounce_patterns'] ?? [];

        $cutoffDate = now()->subDays($windowDays);

        return self::where('email', $email)
            ->whereIn('bounce_type', $countedTypes)
            ->where('bounced_at', '>=', $cutoffDate)
            ->where(function ($query) use ($patterns) {
                foreach ($patterns as $pattern) {
                    $query->orWhere('bounce_reason', 'like', "%{$pattern}%");
                }
            })
            ->count();
    }

    /**
     * Check if bounce qualifies as a definitive hard bounce
     */
    protected static function isDefinitiveHardBounce(string $bounceType, ?string $reason): bool
    {
        $config = timebank_config('mailing.bounce_thresholds', []);
        $countedTypes = $config['counted_bounce_types'] ?? ['hard'];
        $patterns = $config['definitive_hard_bounce_patterns'] ?? [];

        if (!in_array($bounceType, $countedTypes)) {
            return false;
        }

        if (empty($reason) || empty($patterns)) {
            return false;
        }

        $reasonLower = strtolower($reason);
        foreach ($patterns as $pattern) {
            if (strpos($reasonLower, strtolower($pattern)) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Suppress email due to threshold being reached
     */
    protected static function suppressEmailByThreshold(string $email, string $reason, int $bounceCount): void
    {
        // Update the latest bounce record to mark as suppressed
        self::where('email', $email)
            ->where('is_suppressed', false)
            ->update(['is_suppressed' => true]);

        Log::warning("Email {$email} suppressed due to {$bounceCount} hard bounces. Latest reason: {$reason}");
    }

    /**
     * Reset email verification for all profile types using this email
     */
    protected static function resetEmailVerificationForAddress(string $email, string $reason): void
    {
        $updatedProfiles = [];

        // Reset verification for all profile types
        $userUpdated = User::where('email', $email)->whereNotNull('email_verified_at')->update(['email_verified_at' => null]);
        if ($userUpdated) $updatedProfiles[] = "Users: {$userUpdated}";

        $orgUpdated = Organization::where('email', $email)->whereNotNull('email_verified_at')->update(['email_verified_at' => null]);
        if ($orgUpdated) $updatedProfiles[] = "Organizations: {$orgUpdated}";

        $bankUpdated = Bank::where('email', $email)->whereNotNull('email_verified_at')->update(['email_verified_at' => null]);
        if ($bankUpdated) $updatedProfiles[] = "Banks: {$bankUpdated}";

        $adminUpdated = Admin::where('email', $email)->whereNotNull('email_verified_at')->update(['email_verified_at' => null]);
        if ($adminUpdated) $updatedProfiles[] = "Admins: {$adminUpdated}";

        if (!empty($updatedProfiles)) {
            Log::warning("Reset email verification for {$email} due to hard bounce threshold. Affected: " . implode(', ', $updatedProfiles) . ". Reason: {$reason}");
        }
    }

    /**
     * Mark that verification has been reset for this email (to prevent multiple resets)
     */
    protected static function markVerificationReset(string $email): void
    {
        // We could add a verification_reset_at column to track this, but for now
        // we'll rely on the email_verified_at being null to prevent duplicate resets
    }

    /**
     * Check if verification has already been reset for this email
     */
    protected static function hasVerificationBeenReset(string $email): bool
    {
        // Check if any profile with this email has null email_verified_at
        return User::where('email', $email)->whereNull('email_verified_at')->exists()
            || Organization::where('email', $email)->whereNull('email_verified_at')->exists()
            || Bank::where('email', $email)->whereNull('email_verified_at')->exists()
            || Admin::where('email', $email)->whereNull('email_verified_at')->exists();
    }

    /**
     * Public method for testing pattern matching
     */
    public static function testPatternMatching(string $bounceType, ?string $reason): bool
    {
        return self::isDefinitiveHardBounce($bounceType, $reason);
    }

    /**
     * Get bounce statistics for an email address
     */
    public static function getBounceStats(string $email): array
    {
        $windowDays = timebank_config('bulk_mail.bounce_thresholds.counting_window_days', 30);
        $cutoffDate = now()->subDays($windowDays);

        $totalBounces = self::where('email', $email)->count();
        $recentBounces = self::where('email', $email)->where('bounced_at', '>=', $cutoffDate)->count();
        $recentHardBounces = self::countRecentDefinitiveBounces($email, $windowDays);
        $isSuppressed = self::isSuppressed($email);

        return [
            'email' => $email,
            'total_bounces' => $totalBounces,
            'recent_bounces' => $recentBounces,
            'recent_hard_bounces' => $recentHardBounces,
            'is_suppressed' => $isSuppressed,
            'window_days' => $windowDays,
        ];
    }
}