"""Mailbox processing service for wp_invoices_mail_app."""

from __future__ import annotations

from contextlib import contextmanager
from email.utils import parseaddr

from apps.wp_invoices_mail_app.auth import is_authorized_from_message
from apps.wp_invoices_mail_app.config import MailConfig
from apps.wp_invoices_mail_app.email_client import (
    extract_invoice_attachments,
    fetch_unseen_messages,
    has_inline_images,
    save_attachments,
    send_processed_invoices_email,
)
from apps.wp_invoices_mail_app.processor import (
    build_email_body_for_results,
    process_attachments_with_wp_invoices,
)
from apps.wp_invoices_mail_app.renderers import (
    render_no_attachments_html,
    render_results_email_html,
)
from apps.wp_invoices_mail_app.storage_paths import ensure_tenant_mail_paths, resolve_tenant_id


@contextmanager
def _mailbox_config(mailbox, tenant_id):
    tenant_paths = ensure_tenant_mail_paths(tenant_id)
    original = {
        "IMAP_HOST": MailConfig.IMAP_HOST,
        "IMAP_PORT": MailConfig.IMAP_PORT,
        "IMAP_USERNAME": MailConfig.IMAP_USERNAME,
        "IMAP_PASSWORD": MailConfig.IMAP_PASSWORD,
        "SMTP_HOST": MailConfig.SMTP_HOST,
        "SMTP_PORT": MailConfig.SMTP_PORT,
        "SMTP_USERNAME": MailConfig.SMTP_USERNAME,
        "SMTP_PASSWORD": MailConfig.SMTP_PASSWORD,
        "FROM_ADDRESS": MailConfig.FROM_ADDRESS,
        "INBOX_DIR": MailConfig.INBOX_DIR,
    }

    try:
        host = mailbox.get("host") or MailConfig.IMAP_HOST
        port = int(mailbox.get("port") or MailConfig.IMAP_PORT)
        username = mailbox.get("username") or MailConfig.IMAP_USERNAME
        password = mailbox.get("password") or MailConfig.IMAP_PASSWORD

        MailConfig.IMAP_HOST = host
        MailConfig.IMAP_PORT = port
        MailConfig.IMAP_USERNAME = username
        MailConfig.IMAP_PASSWORD = password
        MailConfig.SMTP_HOST = host or MailConfig.SMTP_HOST
        MailConfig.SMTP_USERNAME = username or MailConfig.SMTP_USERNAME
        MailConfig.SMTP_PASSWORD = password or MailConfig.SMTP_PASSWORD
        MailConfig.FROM_ADDRESS = username or MailConfig.FROM_ADDRESS
        MailConfig.INBOX_DIR = tenant_paths["inbox"]
        yield
    finally:
        for key, value in original.items():
            setattr(MailConfig, key, value)


def process_mailbox(mailbox, context):
    tenant_id = resolve_tenant_id(context)
    mailbox_id = mailbox.get("id") or mailbox.get("username") or "default"
    folder = mailbox.get("folder") or "INBOX"
    send_response_email = mailbox.get("send_response_email", True)

    print(f"[MAIL] Processing mailbox: {mailbox.get('username')} ({mailbox.get('id')})")
    print(f"[IMAP] Connecting to {mailbox.get('host')}:{mailbox.get('port')}")

    with _mailbox_config(mailbox, tenant_id):
        imap, messages = fetch_unseen_messages(folder=folder)
        if not imap:
            print(f"No se pudo conectar a IMAP para mailbox={mailbox_id}.")
            return

        print("[IMAP] Connected successfully")

        if not messages:
            imap.logout()
            return

        for msg_id, msg in messages:
            from_header = msg.get("From", "")
            _, from_email = parseaddr(from_header)
            subject = msg.get("Subject", "(sin asunto)")

            authorized, auth_msg = is_authorized_from_message(msg, context=context)

            if authorized in (True, "AUTH"):
                print(f"[AUTH] {auth_msg} Desde: {from_email}, asunto: {subject}")

                attachments = extract_invoice_attachments(msg)

                if not attachments:
                    print(f"Correo sin adjuntos válidos desde {from_email}, asunto: {subject}")

                    inline_photos = has_inline_images(msg)
                    text_lines = [
                        "Hi,",
                        "",
                        (
                            "We received your email but could not process any invoice "
                            "because we did not find a valid attachment."
                        ),
                        "",
                    ]

                    if inline_photos:
                        text_lines.append(
                            "It looks like you inserted a photo inside the email body. "
                            "Please attach the invoice as a file using the paper-clip icon "
                            "instead of pasting it into the message text."
                        )
                    else:
                        text_lines.append(
                            "Please attach at least one invoice as a PDF or a clear image file "
                            "(JPG, PNG, etc.) so the bot can process it."
                        )

                    text_lines.extend(
                        [
                            "",
                            "This email was not processed and no PDF was generated.",
                            "",
                            "Regards,",
                            "Invoice Bot – Absolutems",
                        ]
                    )
                    body_text = "\n".join(text_lines)
                    body_html = render_no_attachments_html(inline_photos=inline_photos)

                    if send_response_email:
                        send_processed_invoices_email(
                            to_address=from_email,
                            original_subject=subject,
                            body_text=body_text,
                            pdf_paths=[],
                            body_html=body_html,
                        )

                    imap.store(msg_id, "+FLAGS", "\\Seen")
                    continue

                saved_raw_paths = save_attachments(attachments, MailConfig.INBOX_DIR)
                print("Adjuntos crudos guardados en:")
                for p in saved_raw_paths:
                    print("  -", p)

                results = process_attachments_with_wp_invoices(attachments, context=context)
                error_results = []

                for r in results or []:
                    has_error_flag = ("ok" in r) or ("error" in r) or ("traceback" in r)
                    if has_error_flag and (r.get("ok") is False or r.get("error")):
                        error_results.append(r)

                body = build_email_body_for_results(results) or ""
                body_html = render_results_email_html(results)

                if error_results:
                    extra_lines = [
                        "",
                        "⚠️ Algunas facturas no se pudieron procesar correctamente:",
                    ]

                    for er in error_results:
                        fname = er.get("filename") or er.get("original_filename") or "(sin nombre)"
                        err_text = er.get("error") or "Error desconocido"
                        extra_lines.append(f"  - {fname}: {err_text}")

                    extra_lines.extend(
                        [
                            "",
                            "Si quieres que investiguemos el problema, reenvía este correo a soporte "
                            "incluyendo el bloque de detalles técnicos que ves a continuación.",
                            "",
                            "──────── Detalles técnicos para soporte ────────",
                        ]
                    )

                    for er in error_results:
                        tb = (er.get("traceback") or "").strip()
                        if not tb:
                            continue
                        if len(tb) > 2000:
                            tb = tb[-2000:]
                        fname = er.get("filename") or er.get("original_filename") or "(sin nombre)"
                        extra_lines.append(f"[{fname}]")
                        extra_lines.append(tb)
                        extra_lines.append("")

                    body = (body + "\n" + "\n".join(extra_lines)).strip()

                pdf_paths = []
                for r in results or []:
                    p = r.get("revision_pdf_path") or r.get("pdf_path")
                    if p:
                        pdf_paths.append(p)

                print("PDFs de revisión a adjuntar:")
                for p in pdf_paths:
                    print("  -", p)

                if from_email and send_response_email:
                    send_processed_invoices_email(
                        to_address=from_email,
                        original_subject=subject,
                        body_text=body,
                        body_html=body_html,
                        pdf_paths=pdf_paths,
                    )

                imap.store(msg_id, "+FLAGS", "\\Seen")
                continue

            print(f"[AUTH] {auth_msg} Desde: {from_email}, asunto: {subject}")
            imap.store(msg_id, "+FLAGS", "\\Seen")

        imap.close()
        imap.logout()
