<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use App\Models\User;
use App\Models\Organization;
use App\Models\Admin;
use App\Models\Bank;
use App\Models\Account;
use App\Mail\CallBlockedMail;
use App\Mail\CallExpiredMail;
use App\Mail\CallExpiringMail;
use App\Mail\InactiveProfileWarning1Mail;
use App\Models\Call;
use App\Mail\InactiveProfileWarning2Mail;
use App\Mail\InactiveProfileWarningFinalMail;
use App\Mail\UserDeletedMail;
use App\Mail\TransferReceived;
use App\Mail\ProfileLinkChangedMail;
use App\Mail\ProfileEditedByAdminMail;
use App\Mail\VerifyProfileEmailMailable;
use App\Mail\ReservationCreatedMail;
use App\Mail\ReservationCancelledMail;
use App\Mail\ReservationUpdateMail;
use App\Mail\ReactionCreatedMail;
use App\Mail\TagAddedMail;

class SendTestEmail extends Command
{
    protected $signature = 'email:send-test
                            {--type= : Email type to send (use --list to see all types)}
                            {--receiver= : Receiver type (user, organization, admin, bank)}
                            {--id= : Receiver ID}
                            {--list : List all available email types}
                            {--queue : Send via queue instead of immediately}';

    protected $description = 'Send test mailing transactional emails for testing and review';

    protected $emailTypes = [
        'inactive-warning-1' => [
            'class' => InactiveProfileWarning1Mail::class,
            'description' => 'Inactive profile warning 1 (first warning)',
            'supports' => ['user', 'organization'],
        ],
        'inactive-warning-2' => [
            'class' => InactiveProfileWarning2Mail::class,
            'description' => 'Inactive profile warning 2 (second warning)',
            'supports' => ['user', 'organization'],
        ],
        'inactive-warning-final' => [
            'class' => InactiveProfileWarningFinalMail::class,
            'description' => 'Inactive Profile Final Warning (last warning)',
            'supports' => ['user', 'organization'],
        ],
        'user-deleted' => [
            'class' => UserDeletedMail::class,
            'description' => 'User Deleted Notification',
            'supports' => ['user'],
        ],
        'transfer-received' => [
            'class' => TransferReceived::class,
            'description' => 'Transfer/Payment Received Notification',
            'supports' => ['user', 'organization'],
        ],
        'profile-link-changed' => [
            'class' => ProfileLinkChangedMail::class,
            'description' => 'Profile Link/Name Changed Notification',
            'supports' => ['user', 'organization', 'admin', 'bank'],
        ],
        'profile-edited-by-admin' => [
            'class' => ProfileEditedByAdminMail::class,
            'description' => 'Profile Edited by Admin Notification',
            'supports' => ['user', 'organization'],
        ],
        'verify-email' => [
            'class' => VerifyProfileEmailMailable::class,
            'description' => 'Email Verification Request',
            'supports' => ['user', 'organization'],
        ],
        'reservation-created' => [
            'class' => ReservationCreatedMail::class,
            'description' => 'Reservation Created Notification',
            'supports' => ['user', 'organization'],
        ],
        'reservation-cancelled' => [
            'class' => ReservationCancelledMail::class,
            'description' => 'Reservation Cancelled Notification',
            'supports' => ['user', 'organization'],
        ],
        'reservation-updated' => [
            'class' => ReservationUpdateMail::class,
            'description' => 'Reservation Updated Notification',
            'supports' => ['user', 'organization'],
        ],
        'reaction-created' => [
            'class' => ReactionCreatedMail::class,
            'description' => 'Reaction/Comment Created Notification',
            'supports' => ['user', 'organization'],
        ],
        'tag-added' => [
            'class' => TagAddedMail::class,
            'description' => 'Tag Added to Profile Notification',
            'supports' => ['user', 'organization'],
        ],
        'call-expired' => [
            'class' => CallExpiredMail::class,
            'description' => 'Call Expired Notification',
            'supports' => ['user', 'organization', 'bank'],
        ],
        'call-expiring' => [
            'class' => CallExpiringMail::class,
            'description' => 'Call Expiring Soon Warning',
            'supports' => ['user', 'organization', 'bank'],
        ],
        'call-blocked' => [
            'class' => CallBlockedMail::class,
            'description' => 'Call Blocked by Admin Notification',
            'supports' => ['user', 'organization', 'bank'],
        ],
    ];

    public function handle()
    {
        if ($this->option('list')) {
            return $this->listEmailTypes();
        }

        $type = $this->option('type');
        $receiverType = $this->option('receiver');
        $receiverId = $this->option('id');

        // Interactive mode if no options provided
        if (!$type || !$receiverType || !$receiverId) {
            return $this->interactiveMode();
        }

        return $this->sendEmail($type, $receiverType, $receiverId);
    }

    protected function listEmailTypes()
    {
        $this->info('Available Email Types:');
        $this->newLine();

        foreach ($this->emailTypes as $key => $config) {
            $supports = implode(', ', $config['supports']);
            $this->line("  <fg=cyan>{$key}</>");
            $this->line("    Description: {$config['description']}");
            $this->line("    Supports: {$supports}");
            $this->newLine();
        }

        $this->info('Usage Example:');
        $this->line('  php artisan email:send-test --type=inactive-warning-1 --receiver=user --id=102');
        $this->newLine();

        return 0;
    }

    protected function interactiveMode()
    {
        $this->info('📧 Test Email Sender - Interactive Mode');
        $this->newLine();

        // Select email type
        $typeChoices = array_map(
            fn ($key, $config) => "{$key} - {$config['description']}",
            array_keys($this->emailTypes),
            array_values($this->emailTypes)
        );

        $selectedIndex = array_search(
            $this->choice('Select email type', $typeChoices),
            $typeChoices
        );
        $type = array_keys($this->emailTypes)[$selectedIndex];

        // Select receiver type
        $supports = $this->emailTypes[$type]['supports'];
        $receiverType = $this->choice('Select receiver type', $supports);

        // Enter receiver ID
        $receiverId = $this->ask('Enter receiver ID');

        return $this->sendEmail($type, $receiverType, $receiverId);
    }

    protected function sendEmail($type, $receiverType, $receiverId)
    {
        if (!isset($this->emailTypes[$type])) {
            $this->error("Invalid email type: {$type}");
            $this->info('Use --list to see all available types');
            return 1;
        }

        $config = $this->emailTypes[$type];

        if (!in_array($receiverType, $config['supports'])) {
            $this->error("Email type '{$type}' does not support receiver type '{$receiverType}'");
            $this->info('Supported types: ' . implode(', ', $config['supports']));
            return 1;
        }

        // Get receiver profile
        $receiver = $this->getReceiver($receiverType, $receiverId);
        if (!$receiver) {
            $this->error("Receiver not found: {$receiverType} #{$receiverId}");
            return 1;
        }

        $this->info("Sending '{$type}' email to {$receiver->name} ({$receiver->email})");
        $this->newLine();

        try {
            $mailable = $this->buildMailable($type, $receiver, $receiverType);

            if ($this->option('queue')) {
                Mail::to($receiver->email)->queue($mailable);
                $this->info('✅ Email queued successfully');
                $this->line('Run queue worker: php artisan queue:work --stop-when-empty');
            } else {
                Mail::to($receiver->email)->send($mailable);
                $this->info('✅ Email sent successfully');
            }

            $this->newLine();
            $this->line("Recipient: {$receiver->email}");
            $this->line("Profile: {$receiver->name}");
            $this->line("Language: " . ($receiver->lang_preference ?? 'en'));

            return 0;
        } catch (\Exception $e) {
            $this->error('Failed to send email: ' . $e->getMessage());
            $this->line($e->getTraceAsString());
            return 1;
        }
    }

    protected function getReceiver($type, $id)
    {
        return match($type) {
            'user' => User::find($id),
            'organization' => Organization::find($id),
            'admin' => Admin::find($id),
            'bank' => Bank::find($id),
            default => null,
        };
    }

    protected function buildMailable($type, $receiver, $receiverType)
    {
        // Get test data
        $accounts = $this->getAccountsData($receiver);
        $totalBalance = $this->getTotalBalance($accounts);

        return match($type) {
            'inactive-warning-1' => new InactiveProfileWarning1Mail(
                $receiver,
                ucfirst($receiverType),
                '2 weeks',
                14,
                $accounts,
                $totalBalance,
                351
            ),
            'inactive-warning-2' => new InactiveProfileWarning2Mail(
                $receiver,
                ucfirst($receiverType),
                '1 week',
                7,
                $accounts,
                $totalBalance,
                358
            ),
            'inactive-warning-final' => new InactiveProfileWarningFinalMail(
                $receiver,
                ucfirst($receiverType),
                '24 hours',
                1,
                $accounts,
                $totalBalance,
                365
            ),
            'user-deleted' => new UserDeletedMail(
                $receiver,
                $accounts,
                $totalBalance,
                $this->getTransferTargetAccount()
            ),
            'transfer-received' => $this->buildTransferReceivedMail($receiver),
            'profile-link-changed' => new ProfileLinkChangedMail(
                $receiver,
                $this->getLinkedProfileForTest($receiver),
                'attached'
            ),
            'profile-edited-by-admin' => new ProfileEditedByAdminMail(
                $receiver,
                'Test Admin',
                'Updated profile information for testing purposes'
            ),
            'verify-email' => new VerifyProfileEmailMailable(
                $receiver->email,
                url('/verify-email/' . base64_encode($receiver->email))
            ),
            'reservation-created' => $this->buildReservationMail($receiver, ReservationCreatedMail::class),
            'reservation-cancelled' => $this->buildReservationMail($receiver, ReservationCancelledMail::class),
            'reservation-updated' => $this->buildReservationMail($receiver, ReservationUpdateMail::class),
            'reaction-created' => $this->buildReactionMail($receiver),
            'tag-added'     => $this->buildTagAddedMail($receiver),
            'call-expired'  => $this->buildCallExpiredMail($receiver, $receiverType),
            'call-expiring' => $this->buildCallExpiringMail($receiver, $receiverType),
            'call-blocked'  => $this->buildCallBlockedMail($receiver, $receiverType),
            default => throw new \Exception("Mailable builder not implemented for type: {$type}"),
        };
    }

    protected function getAccountsData($profile)
    {
        $accounts = [];
        $profileAccounts = $profile->accounts()->active()->notRemoved()->get();

        foreach ($profileAccounts as $account) {
            \Cache::forget("account_balance_{$account->id}");
            $accounts[] = [
                'id' => $account->id,
                'name' => $account->name,
                'balance' => $account->balance,
                'balanceFormatted' => tbFormat($account->balance),
            ];
        }

        return $accounts;
    }

    protected function getTotalBalance($accounts)
    {
        return array_sum(array_column($accounts, 'balance'));
    }

    protected function getTransferTargetAccount()
    {
        // Get a random organization account or create test data
        $account = Account::whereHasMorph('accountable', [Organization::class])
            ->active()
            ->notRemoved()
            ->first();

        return $account ? [
            'id' => $account->id,
            'name' => $account->name,
        ] : [
            'id' => 1,
            'name' => 'Test Organization Account',
        ];
    }

    protected function buildTransferReceivedMail($receiver)
    {
        $senderAccount = $receiver->accounts()->active()->notRemoved()->first();

        if (!$senderAccount) {
            throw new \Exception('Receiver has no active accounts');
        }

        return new TransferReceived(
            $receiver->name,
            120, // 2 hours in minutes
            tbFormat(120),
            'Test Transfer',
            $senderAccount->name,
            $receiver->email,
            url('/profile/' . $receiver->name)
        );
    }

    protected function buildReservationMail($receiver, $mailClass)
    {
        $postTitle = 'Test Post - ' . $mailClass;
        $postOwner = 'Test Post Owner';
        $postUrl = url('/posts/test-post');
        $reservationDate = now()->addDays(7)->format('Y-m-d H:i');

        return new $mailClass(
            $receiver->name,
            $postTitle,
            $postOwner,
            $postUrl,
            $reservationDate
        );
    }

    protected function buildReactionMail($receiver)
    {
        return new ReactionCreatedMail(
            $receiver->name,
            'Test Commenter',
            'Test Post Title',
            'This is a test comment for email testing purposes.',
            url('/posts/test-post')
        );
    }

    protected function buildTagAddedMail($receiver)
    {
        return new TagAddedMail(
            $receiver->name,
            'Test Tag',
            'Test Admin',
            url('/profile/' . $receiver->name)
        );
    }

    protected function getTestCall($receiver): Call
    {
        return Call::where('callable_type', get_class($receiver))
            ->where('callable_id', $receiver->id)
            ->with(['tag'])
            ->first()
            ?? Call::with(['tag'])->first()
            ?? throw new \Exception('No calls found for test');
    }

    protected function buildCallExpiredMail($receiver, $receiverType): CallExpiredMail
    {
        return new CallExpiredMail($this->getTestCall($receiver), $receiver, ucfirst($receiverType));
    }

    protected function buildCallExpiringMail($receiver, $receiverType): CallExpiringMail
    {
        return new CallExpiringMail($this->getTestCall($receiver), $receiver, ucfirst($receiverType), 7);
    }

    protected function buildCallBlockedMail($receiver, $receiverType): CallBlockedMail
    {
        return new CallBlockedMail($this->getTestCall($receiver), $receiver, ucfirst($receiverType));
    }

    protected function getLinkedProfileForTest($receiver)
    {
        // Find a different profile type to use as the linked profile
        // If receiver is a User, find an Organization/Admin/Bank to link
        // If receiver is Organization/Admin/Bank, find a User to link

        if ($receiver instanceof User) {
            // Try to find an organization first, then admin, then bank
            $linked = Organization::first() ?? Admin::first() ?? Bank::first();
        } else {
            // For Organization/Admin/Bank, find a user
            $linked = User::first();
        }

        // If we can't find any other profile, just return the same receiver
        return $linked ?? $receiver;
    }
}
