import smtplib
import base64
import logging
import hashlib
import time
import re
from pathlib import Path
from datetime import datetime
from typing import Dict, Any, List, Optional
import anyio
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.utils import formatdate, make_msgid
from pydantic import EmailStr
from fastapi import BackgroundTasks
from app.core.settings import settings

logger = logging.getLogger(__name__)

BASE_DIR = Path(__file__).resolve().parent.parent.parent
TEMPLATE_FOLDER = BASE_DIR / "templates"
ASSETS_FOLDER = BASE_DIR / "app" / "assets"

if not TEMPLATE_FOLDER.exists():
    logger.error(f"Email template folder not found at: {TEMPLATE_FOLDER.resolve()}")

if not ASSETS_FOLDER.exists():
    ASSETS_FOLDER = BASE_DIR / "assets"

def render_template_sync(template_name: str, context: Dict[str, Any]) -> str:
    """Loads and renders a template with {variable} syntax."""
    # Try multiple search paths
    search_paths = [
        TEMPLATE_FOLDER / template_name,
        TEMPLATE_FOLDER / "html" / template_name,
        TEMPLATE_FOLDER / "text" / template_name
    ]

    template_content = None
    for path in search_paths:
        if path.exists():
            with open(path, "r", encoding="utf-8") as f:
                template_content = f.read()
            break

    if template_content is None:
        logger.error(f"Template not found: {template_name}")
        return f"Error: Template {template_name} not found."

    # Replace {variable} with context values
    rendered = template_content
    for key, value in context.items():
        pattern = r'\{' + re.escape(key) + r'\}'
        rendered = re.sub(pattern, str(value), rendered)

    return rendered

class EmailService:
    @staticmethod
    def _send_email_smtp_task(
        subject: str,
        email_to: EmailStr,
        template_body: Dict[str, Any],
        template_name: str
    ):
        """Internal helper to send email via SMTP (runs in background)."""
        html_content = render_template_sync(template_name, template_body)

        msg = MIMEMultipart('alternative')
        msg['Subject'] = subject
        msg['From'] = f"{settings.SMTP_FROM_NAME} <{settings.SMTP_FROM}>"
        msg['To'] = email_to
        msg['Date'] = formatdate(localtime=True)
        msg['Message-ID'] = make_msgid()

        msg.attach(MIMEText(html_content, 'html'))

        try:
            host = settings.SMTP_HOST
            port = settings.SMTP_PORT

            if port == 465:
                server = smtplib.SMTP_SSL(host, port, timeout=15)
            else:
                server = smtplib.SMTP(host, port, timeout=15)
                server.starttls()

            server.login(settings.SMTP_USER, settings.SMTP_PASS)
            server.sendmail(settings.SMTP_FROM, [email_to], msg.as_string())
            server.quit()

            logger.info(f"Email sent successfully to {email_to}")
        except Exception as e:
            logger.error(f"Failed to send email to {email_to} via SMTP: {e}")

    @staticmethod
    def _add_task(
        background_tasks: BackgroundTasks,
        subject: str,
        email_to: EmailStr,
        template_body: Dict[str, Any],
        template_name: str
    ):
        background_tasks.add_task(
            EmailService._send_email_smtp_task,
            subject,
            email_to,
            template_body,
            template_name
        )

    # Standard static methods
    @staticmethod
    def send_user_welcome_email(background_tasks: BackgroundTasks, email_to: EmailStr, name: str):
        EmailService._add_task(background_tasks, "Welcome to AeroMail!", email_to, {"name": name, "title": "Welcome!"}, "onboarding_welcome.html")

    @staticmethod
    def send_waitlist_email(background_tasks: BackgroundTasks, email_to: EmailStr, name: str):
        EmailService._add_task(background_tasks, "You're on the Waitlist!", email_to, {"name": name, "title": "Waitlist Confirmation"}, "waitlist.html")

    @staticmethod
    def send_email_verification(background_tasks: BackgroundTasks, email_to: EmailStr, name: str, verification_code: str):
        EmailService._add_task(background_tasks, "Verify Your Email Address", email_to, {"name": name, "user_name": name, "verification_code": verification_code, "title": "Verify Your Email"}, "email_verification.html")

    @staticmethod
    def send_email_verified_notice(background_tasks: BackgroundTasks, email_to: EmailStr, name: str):
        EmailService._add_task(background_tasks, "Email Verified Successfully!", email_to, {"name": name, "user_name": name, "title": "Email Verified"}, "email_verified_notice.html")

    @staticmethod
    def send_password_reset_email(background_tasks: BackgroundTasks, email_to: EmailStr, name: str, reset_link: str):
        EmailService._add_task(background_tasks, "Reset Your Password", email_to, {"name": name, "user_name": name, "reset_link": reset_link, "title": "Reset Password"}, "password_reset.html")

    @staticmethod
    def send_password_change_notice(background_tasks: BackgroundTasks, email_to: EmailStr, name: str):
        EmailService._add_task(background_tasks, "Security Alert: Your Password Was Changed", email_to, {"name": name, "user_name": name, "title": "Password Changed"}, "password_change_notice.html")

    @staticmethod
    def send_email_change_notice(background_tasks: BackgroundTasks, email_to: EmailStr, name: str, old_email: str):
        EmailService._add_task(background_tasks, "Security Alert: Your Email Was Changed", email_to, {"name": name, "user_name": name, "new_email": email_to, "old_email": old_email, "title": "Email Changed"}, "email_change_notice.html")

    @staticmethod
    def send_purchase_success_email(background_tasks: BackgroundTasks, email_to: EmailStr, name: str, service_name: str, amount: float, transaction_ref: str, recipient: str):
        EmailService._add_task(background_tasks, f"Purchase Successful: {service_name}", email_to, {"name": name, "user_name": name, "service_name": service_name, "amount": f"₦{amount:,.2f}", "transaction_ref": transaction_ref, "recipient": recipient, "title": "Purchase Success"}, "purchase_success.html")

    @staticmethod
    def send_purchase_failed_email(background_tasks: BackgroundTasks, email_to: EmailStr, name: str, service_name: str, amount: float, transaction_ref: str, reason: str):
        EmailService._add_task(background_tasks, f"Purchase Failed: {service_name}", email_to, {"name": name, "user_name": name, "service_name": service_name, "amount": f"₦{amount:,.2f}", "transaction_ref": transaction_ref, "reason": reason, "title": "Purchase Failed"}, "purchase_failed.html")

    @staticmethod
    def send_refund_email(background_tasks: BackgroundTasks, email_to: EmailStr, name: str, service_name: str, amount: float, transaction_ref: str):
        EmailService._add_task(background_tasks, "Refund Processed", email_to, {"name": name, "user_name": name, "service_name": service_name, "amount": f"₦{amount:,.2f}", "transaction_ref": transaction_ref, "title": "Refund Notice"}, "refund_processed.html")

    @staticmethod
    def send_ticket_created_email(background_tasks: BackgroundTasks, email_to: str, name: str, ticket_id: str, subject: str, message_preview: str):
        EmailService._add_task(background_tasks, f"Ticket Created: {subject} [#{ticket_id}]", email_to, {"name": name, "ticket_id": ticket_id, "subject": subject, "message_preview": message_preview}, "ticket_created.html")

    @staticmethod
    def send_ticket_reply_email(background_tasks: BackgroundTasks, email_to: str, name: str, ticket_id: str, subject: str, reply_message: str, is_admin_reply: bool = True):
        template = "ticket_reply_admin.html" if is_admin_reply else "ticket_reply_user.html"
        EmailService._add_task(background_tasks, f"New Reply: {subject} [#{ticket_id}]", email_to, {"name": name, "ticket_id": ticket_id, "subject": subject, "reply_message": reply_message}, template)

    @staticmethod
    def send_confess_notification(background_tasks: BackgroundTasks, email_to: str, name: str, sender_name: str, message: str, confess_type: str, slug: str):
        EmailService._add_task(background_tasks, f"You have a new confession from {sender_name}", email_to, {"name": name, "sender_name": sender_name, "message": message, "confess_type": confess_type, "slug": slug, "cta_link": f"{settings.SMTP_HOST}/{slug}"}, "confess_notification.html")

    @staticmethod
    def send_confess_response_notification(background_tasks: BackgroundTasks, email_to: str, sender_name: str, recipient_name: str, response: bool, confess_type: str, slug: str):
        response_text = "Accepted" if response else "Declined"
        EmailService._add_task(background_tasks, f"{recipient_name} has {response_text} your confession", email_to, {"name": sender_name, "recipient_name": recipient_name, "response": response_text, "confess_type": confess_type, "slug": slug, "is_accepted": response}, "confess_response_notification.html")

    @staticmethod
    def send_confess_reschedule_notification(background_tasks: BackgroundTasks, email_to: str, sender_name: str, recipient_name: str, new_date: datetime, confess_type: str, slug: str):
        friendly_date = new_date.strftime("%B %d, %Y at %I:%M %p")
        EmailService._add_task(background_tasks, f"{recipient_name} proposed a new date", email_to, {"name": sender_name, "recipient_name": recipient_name, "new_date": friendly_date, "confess_type": confess_type, "slug": slug}, "confess_reschedule_notification.html")

    @staticmethod
    def send_confess_viewed_notification(background_tasks: BackgroundTasks, email_to: str, sender_name: str, recipient_name: str, confess_type: str, slug: str):
        EmailService._add_task(background_tasks, f"Someone viewed your confession", email_to, {"name": sender_name, "recipient_name": recipient_name, "confess_type": confess_type, "slug": slug}, "confess_viewed_notification.html")

email_service = EmailService()

async def send_email(email: EmailStr, subject: str, body: str) -> bool:
    """Async wrapper that runs synchronous SMTP logic in a separate thread."""
    def _sync_send():
        try:
            msg = MIMEMultipart('alternative')
            msg['Subject'] = subject
            msg['From'] = f"{settings.SMTP_FROM_NAME} <{settings.SMTP_FROM}>"
            msg['To'] = email
            msg['Date'] = formatdate(localtime=True)
            msg['Message-ID'] = make_msgid()
            msg.attach(MIMEText(body, 'html'))

            host = settings.SMTP_HOST
            port = settings.SMTP_PORT

            if port == 465:
                server = smtplib.SMTP_SSL(host, port, timeout=15)
            else:
                server = smtplib.SMTP(host, port, timeout=15)
                server.starttls()

            server.login(settings.SMTP_USER, settings.SMTP_PASS)
            server.sendmail(settings.SMTP_FROM, [email], msg.as_string())
            server.quit()
            return True
        except Exception as e:
            logger.error(f"Campaign send failed: {e}")
            return False

    return await anyio.to_thread.run_sync(_sync_send)
