"""
BizNode Support — Email Monitor
================================
Connects to biznodesupport@1bz.biz via IMAP, polls for new emails,
creates/updates tickets, and auto-responds using Ollama AI.
"""

import email
import email.utils
import imaplib
import io
import json
import logging
import os
import re
import smtplib
import sys
import zipfile
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from pathlib import Path
from typing import Optional

log = logging.getLogger("biznode.support.monitor")

_PROJECT_ROOT = Path(__file__).resolve().parent.parent

IMAP_HOST = os.getenv("SUPPORT_IMAP_HOST", "10.50.0.1")
IMAP_PORT = 993
SMTP_HOST = os.getenv("SUPPORT_SMTP_HOST", "10.50.0.1")
SMTP_PORT = 465
SUPPORT_EMAIL = "biznodesupport@1bz.biz"
POLL_INTERVAL = 180  # 3 minutes

# Regex to detect ticket IDs in subject lines
_TICKET_RE = re.compile(r"\[BizNode Support #(TICKET-\d{4,})\]")


def _load_env():
    env_file = _PROJECT_ROOT / ".env"
    if env_file.exists():
        for line in env_file.read_text(encoding="utf-8").splitlines():
            line = line.strip()
            if line and not line.startswith("#") and "=" in line:
                k, v = line.split("=", 1)
                os.environ.setdefault(k.strip(), v.strip())

    admin_env = _PROJECT_ROOT / "tools" / "admin" / "admin.env"
    if admin_env.exists():
        for line in admin_env.read_text(encoding="utf-8").splitlines():
            line = line.strip()
            if line and not line.startswith("#") and "=" in line:
                k, v = line.split("=", 1)
                os.environ.setdefault(k.strip(), v.strip())


def _get_password() -> str:
    admin_env = _PROJECT_ROOT / "tools" / "admin" / "admin.env"
    if admin_env.exists():
        for line in admin_env.read_text(encoding="utf-8").splitlines():
            line = line.strip()
            if line.startswith("SUPPORT_EMAIL_PASSWORD="):
                val = line.split("=", 1)[1].strip()
                if val and val != "CHANGEME_set_real_password_here":
                    return val
    return os.getenv("SUPPORT_EMAIL_PASSWORD", "")


def _get_telegram_token() -> str:
    env_file = _PROJECT_ROOT / ".env"
    if env_file.exists():
        for line in env_file.read_text(encoding="utf-8").splitlines():
            if line.strip().startswith("TELEGRAM_BOT_TOKEN="):
                return line.strip().split("=", 1)[1].strip()
    return os.getenv("TELEGRAM_BOT_TOKEN", "")


def _notify_telegram(text: str):
    token = _get_telegram_token()
    chat_id = "7668967550"
    if not token:
        return
    try:
        import requests
        requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": chat_id, "text": text, "parse_mode": "Markdown"},
            timeout=10,
        )
    except Exception as exc:
        log.warning("Telegram notify failed: %s", exc)


def _send_html_email(to_addr: str, subject: str, html_body: str) -> bool:
    password = _get_password()
    if not password:
        log.error("SUPPORT_EMAIL_PASSWORD not configured")
        return False
    try:
        msg = MIMEMultipart("alternative")
        msg["From"] = f"BizNode Support <{SUPPORT_EMAIL}>"
        msg["To"] = to_addr
        msg["Subject"] = subject
        msg.attach(MIMEText(html_body, "html", "utf-8"))

        with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, timeout=30) as server:
            server.login(SUPPORT_EMAIL, password)
            server.sendmail(SUPPORT_EMAIL, to_addr, msg.as_string())
        log.info("Email sent to %s — %s", to_addr, subject[:60])
        return True
    except Exception as exc:
        log.error("Failed to send email to %s: %s", to_addr, exc)
        return False


def _extract_text_from_email(msg: email.message.Message) -> tuple:
    body = ""
    attachment_texts = []
    attachment_names = []
    has_logs = False

    if msg.is_multipart():
        for part in msg.walk():
            content_type = part.get_content_type()
            disposition = str(part.get("Content-Disposition", ""))

            if "attachment" in disposition:
                filename = part.get_filename() or "attachment"
                attachment_names.append(filename)
                payload = part.get_payload(decode=True)
                if not payload:
                    continue

                if filename.endswith(".zip"):
                    has_logs = True
                    try:
                        with zipfile.ZipFile(io.BytesIO(payload)) as zf:
                            for name in zf.namelist():
                                if name.endswith((".log", ".txt", ".err", ".out")):
                                    with zf.open(name) as f:
                                        content = f.read().decode("utf-8", errors="replace")
                                        attachment_texts.append(f"--- {name} ---\n{content[:5000]}")
                    except Exception as exc:
                        log.warning("Failed to extract zip %s: %s", filename, exc)

                elif filename.endswith((".log", ".txt", ".err", ".out")):
                    has_logs = True
                    try:
                        attachment_texts.append(
                            f"--- {filename} ---\n" + payload.decode("utf-8", errors="replace")[:5000]
                        )
                    except Exception:
                        pass

            elif content_type == "text/plain":
                payload = part.get_payload(decode=True)
                if payload:
                    body += payload.decode("utf-8", errors="replace")
            elif content_type == "text/html" and not body:
                payload = part.get_payload(decode=True)
                if payload:
                    html = payload.decode("utf-8", errors="replace")
                    body += re.sub(r"<[^>]+>", " ", html)
    else:
        payload = msg.get_payload(decode=True)
        if payload:
            body = payload.decode("utf-8", errors="replace")

    return body.strip(), "\n\n".join(attachment_texts), attachment_names, has_logs


def _extract_ticket_from_subject(subject: str) -> Optional[str]:
    m = _TICKET_RE.search(subject or "")
    if m:
        return m.group(1)
    return None


def process_email(msg: email.message.Message) -> str:
    from support.ticket_manager import (
        create_ticket, update_ticket, add_reply,
        find_open_ticket_for_sender, get_ticket_history_text,
    )
    from support.email_templates import (
        welcome_template, request_logs_template, ai_response_template,
    )
    from support.ollama_analyzer import analyze_issue, analyze_log_file, generate_response

    sender = email.utils.parseaddr(msg.get("From", ""))[1]
    subject = msg.get("Subject", "(No Subject)")
    body, attachment_text, attachment_names, has_logs = _extract_text_from_email(msg)

    existing_ticket = _extract_ticket_from_subject(subject)

    if not existing_ticket:
        existing_ticket = find_open_ticket_for_sender(sender)

    if existing_ticket:
        # --- REPLY to existing ticket ---
        add_reply(existing_ticket, body, "inbound", json.dumps(attachment_names))
        update_ticket(existing_ticket, status="open")

        if has_logs:
            log_analysis = analyze_log_file(attachment_text)
            ai_result = log_analysis["response"]
            html = ai_response_template(existing_ticket, ai_result)
            reply_subject = f"Re: [BizNode Support #{existing_ticket}] {subject}"
            _send_html_email(sender, reply_subject, html)
            add_reply(existing_ticket, ai_result, "outbound")
            update_ticket(existing_ticket, status="waiting_reply", response=ai_result)
        else:
            history = get_ticket_history_text(existing_ticket)
            if len(history.split("\n")) > 4:
                ai_resp = generate_response(history, body)
                html = ai_response_template(existing_ticket, ai_resp)
                reply_subject = f"Re: [BizNode Support #{existing_ticket}] {subject}"
                _send_html_email(sender, reply_subject, html)
                add_reply(existing_ticket, ai_resp, "outbound")
                update_ticket(existing_ticket, status="waiting_reply", response=ai_resp)
            else:
                html = request_logs_template(existing_ticket)
                reply_subject = f"Re: [BizNode Support #{existing_ticket}] Logs Required"
                _send_html_email(sender, reply_subject, html)
                add_reply(existing_ticket, "[Requested logs from customer]", "outbound")
                update_ticket(existing_ticket, status="waiting_reply")

        log.info("Updated %s with reply from %s", existing_ticket, sender)
        return existing_ticket

    else:
        # --- NEW ticket ---
        ticket_id = create_ticket(
            email=sender,
            subject=subject,
            body=body,
            attachments=json.dumps(attachment_names),
            priority="normal",
        )

        html = welcome_template(ticket_id)
        welcome_subject = f"[BizNode Support #{ticket_id}] Welcome — Your Support Request"
        _send_html_email(sender, welcome_subject, html)
        add_reply(ticket_id, "[Welcome email sent with installation guide]", "outbound")
        update_ticket(ticket_id, status="waiting_reply")

        _notify_telegram(
            f"*New Support Ticket #{ticket_id}*\n\n"
            f"From: {sender}\n"
            f"Subject: {subject}\n\n"
            f"{body[:400]}"
        )

        if has_logs:
            analysis = analyze_issue(body, attachment_text)
            ai_html = ai_response_template(ticket_id, analysis["response"])
            ai_subject = f"[BizNode Support #{ticket_id}] Analysis Results"
            _send_html_email(sender, ai_subject, ai_html)
            add_reply(ticket_id, analysis["response"], "outbound")
            update_ticket(ticket_id, response=analysis["response"])

        log.info("Created new %s for %s", ticket_id, sender)
        return ticket_id


def process_existing_unread(msg: email.message.Message) -> str:
    from support.ticket_manager import (
        create_ticket, update_ticket, add_reply,
    )
    from support.email_templates import ai_response_template
    from support.ollama_analyzer import analyze_issue

    sender = email.utils.parseaddr(msg.get("From", ""))[1]
    subject = msg.get("Subject", "(No Subject)")
    body, attachment_text, attachment_names, has_logs = _extract_text_from_email(msg)

    ticket_id = create_ticket(
        email=sender,
        subject=subject,
        body=body,
        attachments=json.dumps(attachment_names),
        priority="normal",
    )

    analysis = analyze_issue(body, attachment_text if has_logs else "")
    html = ai_response_template(ticket_id, analysis["response"])
    reply_subject = f"[BizNode Support #{ticket_id}] {subject}"
    _send_html_email(sender, reply_subject, html)
    add_reply(ticket_id, analysis["response"], "outbound")
    update_ticket(ticket_id, status="waiting_reply", response=analysis["response"])

    _notify_telegram(
        f"*Processed Existing Email #{ticket_id}*\n\n"
        f"From: {sender}\n"
        f"Subject: {subject}"
    )

    return ticket_id


def check_inbox(first_run: bool = False) -> dict:
    password = _get_password()
    if not password:
        return {"error": "SUPPORT_EMAIL_PASSWORD not configured", "processed": 0}

    processed = 0
    errors = []

    try:
        mail = imaplib.IMAP4_SSL(IMAP_HOST, IMAP_PORT, timeout=30)
        mail.login(SUPPORT_EMAIL, password)
        mail.select("INBOX")

        status, data = mail.search(None, "UNSEEN")
        if status != "OK":
            mail.logout()
            return {"error": "IMAP search failed", "processed": 0}

        email_ids = data[0].split()
        for eid in email_ids:
            try:
                status, msg_data = mail.fetch(eid, "(RFC822)")
                if status != "OK":
                    continue
                raw = msg_data[0][1]
                msg = email.message_from_bytes(raw)

                if first_run:
                    process_existing_unread(msg)
                else:
                    process_email(msg)

                mail.store(eid, "+FLAGS", "\\Seen")
                processed += 1
            except Exception as exc:
                log.error("Failed to process email %s: %s", eid, exc)
                errors.append(str(exc))

        mail.logout()
    except Exception as exc:
        log.error("IMAP connection failed: %s", exc)
        return {"error": str(exc), "processed": processed}

    return {"processed": processed, "errors": errors}
