"""Contacts management logic: vCard generation/parsing, database CRUD, and Maildir .Contacts IMAP auto-sync."""

from __future__ import annotations

import datetime
import hashlib
import logging
import os
from pathlib import Path
import re
from typing import Any, Dict, List, Optional

from sqlalchemy import or_
from sqlalchemy.orm import Session

from .models import Contact
from .settings import get_settings

logger = logging.getLogger(__name__)


def generate_vcard(first_name: str, last_name: str, email_addr: str, phone: str = "", company: str = "", address: str = "", notes: str = "") -> str:
    """Generate a standard vCard 3.0 string for a contact."""
    fn = f"{first_name} {last_name}".strip() or email_addr
    lines = [
        "BEGIN:VCARD",
        "VERSION:3.0",
        f"N:{last_name};{first_name};;;",
        f"FN:{fn}",
    ]
    if email_addr:
        lines.append(f"EMAIL;TYPE=INTERNET,PREF:{email_addr}")
    if phone:
        lines.append(f"TEL;TYPE=CELL:{phone}")
    if company:
        lines.append(f"ORG:{company}")
    if address:
        lines.append(f"ADR;TYPE=HOME:;;{address};;;;")
    if notes:
        lines.append(f"NOTE:{notes}")
    lines.append("END:VCARD")
    return "\r\n".join(lines) + "\r\n"


def parse_vcard_content(vcard_text: str) -> Dict[str, str]:
    """Parse vCard 3.0/4.0 text into dictionary of contact fields."""
    fields = {"first_name": "", "last_name": "", "email": "", "phone": "", "company": "", "address": "", "notes": ""}
    for line in vcard_text.splitlines():
        line = line.strip()
        if not line or ":" not in line:
            continue
        hdr, val = line.split(":", 1)
        hdr_upper = hdr.upper()

        if hdr_upper.startswith("N"):
            parts = val.split(";")
            if len(parts) >= 2:
                fields["last_name"] = parts[0].strip()
                fields["first_name"] = parts[1].strip()
        elif hdr_upper.startswith("FN") and not fields["first_name"]:
            fields["first_name"] = val.strip()
        elif hdr_upper.startswith("EMAIL"):
            if not fields["email"]:
                fields["email"] = val.strip()
        elif hdr_upper.startswith("TEL"):
            if not fields["phone"]:
                fields["phone"] = val.strip()
        elif hdr_upper.startswith("ORG"):
            fields["company"] = val.strip()
        elif hdr_upper.startswith("ADR"):
            fields["address"] = val.replace(";", " ").strip()
        elif hdr_upper.startswith("NOTE"):
            fields["notes"] = val.strip()

    return fields


def sync_contact_to_imap_maildir(username: str, contact_id: int, vcard_str: str) -> None:
    """Sync vCard to Maildir .Contacts folder so IMAP clients can read contacts natively."""
    try:
        parts = username.split("@", 1)
        if len(parts) == 2:
            domain, local = parts[1].lower(), parts[0].lower()
            user_dir = Path("/var/mail/vhosts") / domain / local
        else:
            user_dir = Path("/var/mail/vhosts") / username

        contacts_dir = user_dir / ".Contacts" / "cur"
        contacts_dir.mkdir(parents=True, exist_ok=True)

        filename = f"c_{contact_id}.vcf:2,S"
        file_path = contacts_dir / filename
        file_path.write_text(vcard_str, encoding="utf-8")
    except Exception as exc:
        logger.debug("Maildir contacts sync warning for %s: %s", username, exc)


def delete_contact_from_imap_maildir(username: str, contact_id: int) -> None:
    """Remove vCard file from Maildir .Contacts folder."""
    try:
        parts = username.split("@", 1)
        if len(parts) == 2:
            domain, local = parts[1].lower(), parts[0].lower()
            user_dir = Path("/var/mail/vhosts") / domain / local
        else:
            user_dir = Path("/var/mail/vhosts") / username

        file_path = user_dir / ".Contacts" / "cur" / f"c_{contact_id}.vcf:2,S"
        if file_path.is_file():
            file_path.unlink()
    except Exception as exc:
        logger.debug("Maildir contacts unlink warning for %s: %s", username, exc)


def get_account_contacts(db: Session, username: str, query: str = "") -> List[Contact]:
    """Retrieve contacts for a given email account with optional search query."""
    q = db.query(Contact).filter(Contact.account_username == username)
    if query:
        term = f"%{query.strip()}%"
        q = q.filter(
            or_(
                Contact.first_name.ilike(term),
                Contact.last_name.ilike(term),
                Contact.email.ilike(term),
                Contact.company.ilike(term),
            )
        )
    return q.order_by(Contact.first_name, Contact.last_name).all()


def create_account_contact(db: Session, username: str, data: Dict[str, Any]) -> Contact:
    """Create a new contact, save vCard, and sync to IMAP Maildir."""
    fn = str(data.get("first_name", "")).strip()
    ln = str(data.get("last_name", "")).strip()
    em = str(data.get("email", "")).strip()
    ph = str(data.get("phone", "")).strip()
    co = str(data.get("company", "")).strip()
    ad = str(data.get("address", "")).strip()
    nt = str(data.get("notes", "")).strip()

    vcard = generate_vcard(fn, ln, em, ph, co, ad, nt)

    contact = Contact(
        account_username=username,
        first_name=fn,
        last_name=ln,
        email=em,
        phone=ph,
        company=co,
        address=ad,
        notes=nt,
        vcard_data=vcard,
    )
    db.add(contact)
    db.commit()
    db.refresh(contact)

    sync_contact_to_imap_maildir(username, contact.id, vcard)
    return contact


def update_account_contact(db: Session, contact: Contact, data: Dict[str, Any]) -> Contact:
    """Update contact attributes, regenerate vCard, and sync to IMAP Maildir."""
    for key in ("first_name", "last_name", "email", "phone", "company", "address", "notes"):
        if key in data:
            setattr(contact, key, str(data[key]).strip())

    vcard = generate_vcard(
        contact.first_name,
        contact.last_name,
        contact.email,
        contact.phone,
        contact.company,
        contact.address,
        contact.notes,
    )
    contact.vcard_data = vcard
    db.commit()
    db.refresh(contact)

    sync_contact_to_imap_maildir(contact.account_username, contact.id, vcard)
    return contact


def delete_account_contact(db: Session, contact: Contact) -> None:
    """Delete contact record and remove from IMAP Maildir."""
    username = contact.account_username
    cid = contact.id
    db.delete(contact)
    db.commit()
    delete_contact_from_imap_maildir(username, cid)
