<?php

namespace App\Services;

use App\Mail\DynamicEmail;
use App\Models\EmailTemplate;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;
use Exception;

/**
 * EmailService
 * 
 * A comprehensive email service that handles dynamic email sending
 * using database-stored templates with variable substitution.
 * 
 * Features:
 * - Template-based email system
 * - Variable substitution support
 * - User and admin specific templates
 * - Queue support for performance
 * - Error handling and logging
 * - Template validation
 * 
 * @package App\Services
 */
class EmailService
{
    /**
     * Send email using template name and data.
     *
     * @param string $templateName Template identifier
     * @param string $recipientEmail Recipient email address
     * @param array $data Variables for template substitution
     * @param string|null $recipientName Optional recipient name
     * @return bool Success status
     */
    public function sendEmail(string $templateName, string $recipientEmail, array $data = [], ?string $recipientName = null): bool
    {
        try {

            $template = EmailTemplate::getByName($templateName);
            
            if (!$template) {
                return false;
            }

            // Add common variables
            $data = array_merge($data, [
                'recipient_email' => $recipientEmail,
                'recipient_name' => $recipientName ?? 'User',
                'site_name' => config('app.name'),
                'site_url' => config('app.url'),
                'current_year' => date('Y'),
            ]);

            // Send email
            Mail::to($recipientEmail, $recipientName)->send(new DynamicEmail($template, $data));

            return true;

        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Send email to user using template.
     *
     * @param User $user User instance
     * @param string $templateName Template identifier
     * @param array $data Variables for template substitution
     * @return bool Success status
     */
    public function sendToUser(User $user, string $templateName, array $data = []): bool
    {
        return $this->sendEmail($templateName, $user->email, array_merge($data, [
            'user_name' => $user->name,
            'user_firstname' => $user->firstname ?? '',
            'user_lastname' => $user->lastname ?? '',
            'user_id' => $user->id,
        ]), $user->name);
    }

    /**
     * Send email to admin using template.
     *
     * @param string $templateName Template identifier
     * @param array $data Variables for template substitution
     * @return bool Success status
     */
    public function sendToAdmin(string $templateName, array $data = []): bool
    {
        // Get admin email from settings or use default
        $adminEmail = \App\Models\Setting::get('support_email', config('mail.from.address'));
        
        
        if (empty($adminEmail)) {
            return false;
        }
        
        return $this->sendEmail($templateName, $adminEmail, array_merge($data, [
            'admin_name' => 'Administrator',
            'site_name' => config('app.name'),
        ]), 'Administrator');
    }

    /**
     * Send bulk emails to multiple users.
     *
     * @param array $users Array of User instances or email addresses
     * @param string $templateName Template identifier
     * @param array $data Variables for template substitution
     * @return array Results array with success/failure counts
     */
    public function sendBulkEmail(array $users, string $templateName, array $data = []): array
    {
        $results = [
            'total' => count($users),
            'success' => 0,
            'failed' => 0,
            'errors' => [],
        ];

        foreach ($users as $user) {
            if ($user instanceof User) {
                $success = $this->sendToUser($user, $templateName, $data);
            } else {
                $success = $this->sendEmail($templateName, $user, $data);
            }

            if ($success) {
                $results['success']++;
            } else {
                $results['failed']++;
                $results['errors'][] = $user instanceof User ? $user->email : $user;
            }
        }

        return $results;
    }

    /**
     * Get available templates by type and category.
     *
     * @param string $type Template type ('user' or 'admin')
     * @param string|null $category Optional category filter
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function getTemplates(string $type, ?string $category = null)
    {
        $query = EmailTemplate::forType($type)->active();

        if ($category) {
            $query->forCategory($category);
        }

        return $query->get();
    }

    /**
     * Create or update email template.
     *
     * @param array $templateData Template data
     * @return EmailTemplate
     */
    public function createOrUpdateTemplate(array $templateData): EmailTemplate
    {
        return EmailTemplate::updateOrCreate(
            ['name' => $templateData['name']],
            $templateData
        );
    }

    /**
     * Test email template rendering.
     *
     * @param string $templateName Template identifier
     * @param array $data Test data
     * @return array Rendered content
     */
    public function testTemplate(string $templateName, array $data = []): array
    {
        $template = EmailTemplate::getByName($templateName);
        
        if (!$template) {
            throw new Exception("Template not found: {$templateName}");
        }

        return $template->render($data);
    }

    /**
     * Send user registration welcome email.
     */
    public function sendUserWelcome(User $user): bool
    {
        return $this->sendToUser($user, 'user_welcome', [
            'registration_date' => $user->created_at->format('M d, Y'),
        ]);
    }

    /**
     * Send welcome email to user (alias for sendUserWelcome with additional data support).
     *
     * @param User $user User instance
     * @param array $data Additional data for template substitution
     * @return bool Success status
     */
    public function sendWelcome(User $user, array $data = []): bool
    {
        $welcomeData = array_merge([
            'registration_date' => $user->created_at->format('M d, Y'),
        ], $data);

        return $this->sendToUser($user, 'user_welcome', $welcomeData);
    }

    /**
     * Send email verification email.
     */
    public function sendEmailVerification(User $user, string $verificationUrl): bool
    {
        return $this->sendToUser($user, 'user_email_verification', [
            'verification_url' => $verificationUrl,
            'verification_expires' => now()->addHours(24)->format('M d, Y \a\t g:i A'),
        ]);
    }

    /**
     * Send password reset email.
     */
    public function sendPasswordReset(User $user, string $resetUrl): bool
    {
        return $this->sendToUser($user, 'user_password_reset', [
            'reset_url' => $resetUrl,
            'reset_expires' => now()->addHours(1)->format('M d, Y \a\t g:i A'),
        ]);
    }

    /**
     * Send license created notification to user.
     */
    public function sendLicenseCreated(User $user, array $licenseData): bool
    {
        return $this->sendToUser($user, 'user_license_created', array_merge($licenseData, [
            'license_key' => $licenseData['license_key'] ?? '',
            'product_name' => $licenseData['product_name'] ?? '',
            'expires_at' => $licenseData['expires_at'] ?? '',
        ]));
    }

    /**
     * Send license expiration warning to user.
     */
    public function sendLicenseExpiring(User $user, array $licenseData): bool
    {
        return $this->sendToUser($user, 'user_license_expiring', array_merge($licenseData, [
            'license_key' => $licenseData['license_key'] ?? '',
            'product_name' => $licenseData['product_name'] ?? '',
            'expires_at' => $licenseData['expires_at'] ?? '',
            'days_remaining' => $licenseData['days_remaining'] ?? 0,
        ]));
    }

    /**
     * Send license updated notification to user.
     */
    public function sendLicenseUpdated(User $user, array $licenseData): bool
    {
        return $this->sendToUser($user, 'user_license_updated', array_merge($licenseData, [
            'license_key' => $licenseData['license_key'] ?? '',
            'product_name' => $licenseData['product_name'] ?? '',
            'update_type' => $licenseData['update_type'] ?? 'updated',
        ]));
    }

    /**
     * Send product version update notification to user.
     */
    public function sendProductVersionUpdate(User $user, array $productData): bool
    {
        return $this->sendToUser($user, 'user_product_version_update', array_merge($productData, [
            'product_name' => $productData['product_name'] ?? '',
            'old_version' => $productData['old_version'] ?? '',
            'new_version' => $productData['new_version'] ?? '',
            'download_url' => $productData['download_url'] ?? '',
        ]));
    }

    /**
     * Send support ticket created notification to user.
     */
    public function sendTicketCreated(User $user, array $ticketData): bool
    {
        return $this->sendToUser($user, 'user_ticket_created', array_merge($ticketData, [
            'ticket_id' => $ticketData['ticket_id'] ?? '',
            'ticket_subject' => $ticketData['ticket_subject'] ?? '',
            'ticket_status' => $ticketData['ticket_status'] ?? 'open',
        ]));
    }

    /**
     * Send support ticket status update notification to user.
     */
    public function sendTicketStatusUpdate(User $user, array $ticketData): bool
    {
        return $this->sendToUser($user, 'user_ticket_status_update', array_merge($ticketData, [
            'ticket_id' => $ticketData['ticket_id'] ?? '',
            'ticket_subject' => $ticketData['ticket_subject'] ?? '',
            'old_status' => $ticketData['old_status'] ?? '',
            'new_status' => $ticketData['new_status'] ?? '',
        ]));
    }

    /**
     * Send support ticket reply notification to user.
     */
    public function sendTicketReply(User $user, array $ticketData): bool
    {
        return $this->sendToUser($user, 'user_ticket_reply', array_merge($ticketData, [
            'ticket_id' => $ticketData['ticket_id'] ?? '',
            'ticket_subject' => $ticketData['ticket_subject'] ?? '',
            'reply_message' => $ticketData['reply_message'] ?? '',
            'replied_by' => $ticketData['replied_by'] ?? 'Support Team',
        ]));
    }

    /**
     * Send invoice approaching due date notification to user.
     */
    public function sendInvoiceApproachingDue(User $user, array $invoiceData): bool
    {
        return $this->sendToUser($user, 'user_invoice_approaching_due', array_merge($invoiceData, [
            'invoice_number' => $invoiceData['invoice_number'] ?? '',
            'invoice_amount' => $invoiceData['invoice_amount'] ?? 0,
            'due_date' => $invoiceData['due_date'] ?? '',
            'days_remaining' => $invoiceData['days_remaining'] ?? 0,
        ]));
    }

    /**
     * Send invoice paid notification to user.
     */
    public function sendInvoicePaid(User $user, array $invoiceData): bool
    {
        return $this->sendToUser($user, 'user_invoice_paid', array_merge($invoiceData, [
            'invoice_number' => $invoiceData['invoice_number'] ?? '',
            'invoice_amount' => $invoiceData['invoice_amount'] ?? 0,
            'payment_date' => $invoiceData['payment_date'] ?? '',
            'payment_method' => $invoiceData['payment_method'] ?? '',
        ]));
    }

    /**
     * Send invoice cancelled notification to user.
     */
    public function sendInvoiceCancelled(User $user, array $invoiceData): bool
    {
        return $this->sendToUser($user, 'user_invoice_cancelled', array_merge($invoiceData, [
            'invoice_number' => $invoiceData['invoice_number'] ?? '',
            'invoice_amount' => $invoiceData['invoice_amount'] ?? 0,
            'cancellation_reason' => $invoiceData['cancellation_reason'] ?? '',
        ]));
    }

    /**
     * Send admin notification for license created.
     */
    public function sendAdminLicenseCreated(array $licenseData): bool
    {
        return $this->sendToAdmin('admin_license_created', array_merge($licenseData, [
            'license_key' => $licenseData['license_key'] ?? '',
            'product_name' => $licenseData['product_name'] ?? '',
            'customer_name' => $licenseData['customer_name'] ?? '',
            'customer_email' => $licenseData['customer_email'] ?? '',
        ]));
    }

    /**
     * Send admin notification for license expiring.
     */
    public function sendAdminLicenseExpiring(array $licenseData): bool
    {
        return $this->sendToAdmin('admin_license_expiring', array_merge($licenseData, [
            'license_key' => $licenseData['license_key'] ?? '',
            'product_name' => $licenseData['product_name'] ?? '',
            'customer_name' => $licenseData['customer_name'] ?? '',
            'customer_email' => $licenseData['customer_email'] ?? '',
            'expires_at' => $licenseData['expires_at'] ?? '',
            'days_remaining' => $licenseData['days_remaining'] ?? 0,
        ]));
    }

    /**
     * Send admin notification for license renewed.
     */
    public function sendAdminLicenseRenewed(array $licenseData): bool
    {
        return $this->sendToAdmin('admin_license_renewed', array_merge($licenseData, [
            'license_key' => $licenseData['license_key'] ?? '',
            'product_name' => $licenseData['product_name'] ?? '',
            'customer_name' => $licenseData['customer_name'] ?? '',
            'customer_email' => $licenseData['customer_email'] ?? '',
            'new_expires_at' => $licenseData['new_expires_at'] ?? '',
        ]));
    }

    /**
     * Send admin notification for support ticket created.
     */
    public function sendAdminTicketCreated(array $ticketData): bool
    {
        return $this->sendToAdmin('admin_ticket_created', array_merge($ticketData, [
            'ticket_id' => $ticketData['ticket_id'] ?? '',
            'ticket_subject' => $ticketData['ticket_subject'] ?? '',
            'customer_name' => $ticketData['customer_name'] ?? '',
            'customer_email' => $ticketData['customer_email'] ?? '',
            'ticket_priority' => $ticketData['ticket_priority'] ?? 'normal',
        ]));
    }

    /**
     * Send renewal reminder to user.
     */
    public function sendRenewalReminder(User $user, array $renewalData): bool
    {
        return $this->sendToUser($user, 'user_renewal_reminder', array_merge($renewalData, [
            'license_key' => $renewalData['license_key'] ?? '',
            'product_name' => $renewalData['product_name'] ?? '',
            'expires_at' => $renewalData['expires_at'] ?? '',
            'invoice_amount' => $renewalData['invoice_amount'] ?? 0,
            'invoice_due_date' => $renewalData['invoice_due_date'] ?? '',
            'invoice_id' => $renewalData['invoice_id'] ?? '',
        ]));
    }

    /**
     * Send admin notification for renewal reminder.
     */
    public function sendAdminRenewalReminder(array $renewalData): bool
    {
        return $this->sendToAdmin('admin_renewal_reminder', array_merge($renewalData, [
            'license_key' => $renewalData['license_key'] ?? '',
            'product_name' => $renewalData['product_name'] ?? '',
            'customer_name' => $renewalData['customer_name'] ?? '',
            'customer_email' => $renewalData['customer_email'] ?? '',
            'expires_at' => $renewalData['expires_at'] ?? '',
            'invoice_amount' => $renewalData['invoice_amount'] ?? 0,
            'invoice_id' => $renewalData['invoice_id'] ?? '',
        ]));
    }

    /**
     * Send admin notification for ticket reply from user.
     */
    public function sendAdminTicketReply(array $ticketData): bool
    {
        return $this->sendToAdmin('admin_ticket_reply', array_merge($ticketData, [
            'ticket_id' => $ticketData['ticket_id'] ?? '',
            'ticket_subject' => $ticketData['ticket_subject'] ?? '',
            'customer_name' => $ticketData['customer_name'] ?? '',
            'customer_email' => $ticketData['customer_email'] ?? '',
            'reply_message' => $ticketData['reply_message'] ?? '',
        ]));
    }

    /**
     * Send admin notification for ticket closed by user.
     */
    public function sendAdminTicketClosed(array $ticketData): bool
    {
        return $this->sendToAdmin('admin_ticket_closed', array_merge($ticketData, [
            'ticket_id' => $ticketData['ticket_id'] ?? '',
            'ticket_subject' => $ticketData['ticket_subject'] ?? '',
            'customer_name' => $ticketData['customer_name'] ?? '',
            'customer_email' => $ticketData['customer_email'] ?? '',
            'closure_reason' => $ticketData['closure_reason'] ?? '',
        ]));
    }

    /**
     * Send admin notification for invoice approaching due.
     */
    public function sendAdminInvoiceApproachingDue(array $invoiceData): bool
    {
        return $this->sendToAdmin('admin_invoice_approaching_due', array_merge($invoiceData, [
            'invoice_number' => $invoiceData['invoice_number'] ?? '',
            'invoice_amount' => $invoiceData['invoice_amount'] ?? 0,
            'customer_name' => $invoiceData['customer_name'] ?? '',
            'customer_email' => $invoiceData['customer_email'] ?? '',
            'due_date' => $invoiceData['due_date'] ?? '',
            'days_remaining' => $invoiceData['days_remaining'] ?? 0,
        ]));
    }

    /**
     * Send admin notification for invoice cancelled.
     */
    public function sendAdminInvoiceCancelled(array $invoiceData): bool
    {
        return $this->sendToAdmin('admin_invoice_cancelled', array_merge($invoiceData, [
            'invoice_number' => $invoiceData['invoice_number'] ?? '',
            'invoice_amount' => $invoiceData['invoice_amount'] ?? 0,
            'customer_name' => $invoiceData['customer_name'] ?? '',
            'customer_email' => $invoiceData['customer_email'] ?? '',
            'cancellation_reason' => $invoiceData['cancellation_reason'] ?? '',
        ]));
    }
}
