<?php

namespace App\Console\Commands;

use App\Mail\FailedEnquiryReport;
use App\Models\SystemAlert;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Mail;
use Mtc\Crm\Models\EnquiryAction;

/**
 * Command to check for failed enquiry actions and send an alert if failures are detected across tenants.
 */
class CheckFailedEnquiryActions extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'check:failed-enquiry-actions';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Check and alert for failed enquiry actions across tenants';

    /**
     * Execute the console command to check for failed enquiry actions.
     *
     * This method checks for failed enquiry actions in each tenant,
     * and if any failures are found, it sends an alert email.
     *
     * @return int
     */
    public function handle(): int
    {
        if ($this->shouldSkipTask()) {
            return self::SUCCESS;
        }

        // Purge old failures
        $this->purgeOldFailures();

        $allFailures = collect();

        // Run the task for multiple tenants
        tenancy()->runForMultiple(null, function ($tenant) use ($allFailures) {
            // Get the recent failures for the current tenant
            $failedActions = $this->getRecentFailures();

            if ($failedActions->count() > 0) {
                // Add the tenant ID and its failures to the collection
                $allFailures->push([
                    'tenant_id' => $tenant->id,
                    'failures' => $failedActions,
                ]);
            }
        });

        // If any failures were collected, send a consolidated alert
        if ($allFailures->isNotEmpty()) {
            $this->sendFailureAlert($allFailures);
        } else {
            $this->info('No alertable failures were detected for any tenants');
        }

        return self::SUCCESS;
    }

    /**
     * Send a consolidated alert email about failures detected across multiple tenants.
     *
     * @param \Illuminate\Support\Collection $allFailures The failures grouped by tenant.
     *
     * @return void
     */
    private function sendFailureAlert(Collection $allFailures): void
    {
        if ($this->recentAlertExists()) {
            $this->info('Alert suppressed due to frequency limit.');
            return;
        }

        $developerAlertEmails = config('mail.developer_alerts');

        // Extract a tenant ID to send the mail under
        $tenant_id = $allFailures[0]['tenant_id'];

        if (!empty($developerAlertEmails)) {
            foreach ($developerAlertEmails as $email) {
                tenancy()->initialize($tenant_id);

                try {
                    Mail::to($email)->send(new FailedEnquiryReport($allFailures));
                    $this->info('A failed enquiry report has been sent out to ' . $email);
                } catch (\Exception $e) {
                    $this->error('Failed to send failed enquiry report to ' . $email . '. Error: ' . $e->getMessage());
                }
            }
        }

        // Log the alert in the SystemAlert table
        SystemAlert::query()
            ->create([
                'alert_type' => 'enquiry_failure',
                'last_sent_at' => Carbon::now(),
            ]);
    }

    /**
     * Check if a recent alert for enquiry failures already exists within the last day.
     *
     * @return bool True if a recent alert exists, false otherwise.
     */
    private function recentAlertExists(): bool
    {
        return SystemAlert::query()
            ->where('alert_type', 'enquiry_failure')
            ->where('last_sent_at', '>=', Carbon::now()->subDay())
            ->exists();
    }

    /**
     * Get the recent failed enquiry actions for the current tenant.
     *
     * @return \Illuminate\Support\Collection
     */
    private function getRecentFailures(): Collection
    {
        return EnquiryAction::query()
            ->whereNotNull('failed_at')
            ->where('created_at', '>=', Carbon::now()->subDay())
            ->get();
    }

    /**
     * Purge old enquiry failures older than 1 month.
     *
     * This method queries the `SystemAlert` table for records where
     * `failed_at` is not null and the `created_at` timestamp is older than
     * one month. It deletes the matching records and logs the number
     * of deleted records.
     *
     * @return void
     */
    private function purgeOldFailures(): void
    {
        $deleted = SystemAlert::query()
            ->where('alert_type', 'enquiry_failure')
            ->where('last_sent_at', '<', Carbon::now()->subMonth())
            ->delete();

        $this->info("Purged $deleted system alerts older than 1 month.");
    }


    /**
     * Determine if the task should be skipped based on the environment or testing mode.
     *
     * @return bool True if the task should be skipped, false otherwise.
     */
    private function shouldSkipTask(): bool
    {
        // Skip on staging/demo type environments
        return in_array(app()->environment(), ['local', 'production']) === false
            && app()->runningUnitTests() === false;
    }
}
