from __future__ import annotations

import html
import re
from dataclasses import dataclass
from datetime import date, datetime
from decimal import Decimal
from typing import Any


@dataclass(slots=True)
class EmailAttachment:
    """In-memory attachment used by the SMTP email service.

    This avoids writing temporary invoice/receipt files to disk and keeps Phase
    7S.1D independent of any PDF engine. The attachment is currently generated
    as an HTML snapshot, which users can open/print/save as PDF from the mail
    client. A later PDF-rendering phase can reuse the same hook.
    """

    filename: str
    content: bytes
    content_type: str = "application/octet-stream"


def _safe_text(value: Any) -> str:
    if value is None:
        return ""
    if isinstance(value, (date, datetime)):
        return value.isoformat()
    return str(value)


def _safe_filename(value: str, fallback: str) -> str:
    cleaned = re.sub(r"[^A-Za-z0-9_.-]+", "_", (value or "").strip()).strip("_")
    return cleaned or fallback


def _money(value: Any) -> str:
    try:
        amount = Decimal(str(value or "0"))
        return f"₹ {amount:,.2f}"
    except Exception:
        return _safe_text(value)


def _client_name(client: Any) -> str:
    if not client:
        return "Client"
    return (
        getattr(client, "client_name", None)
        or getattr(client, "trade_name", None)
        or getattr(client, "name", None)
        or "Client"
    )


def _invoice_number(invoice: Any) -> str:
    return _safe_text(
        getattr(invoice, "invoice_no", None)
        or getattr(invoice, "invoice_number", None)
        or getattr(invoice, "number", None)
        or getattr(invoice, "id", "invoice")
    )


def _invoice_items(invoice: Any) -> list[Any]:
    for attr in ("items", "line_items", "invoice_items"):
        rows = getattr(invoice, attr, None)
        if rows:
            try:
                return list(rows)
            except Exception:
                return []
    return []


def build_invoice_html(invoice: Any, *, firm_name: str = "") -> str:
    client = getattr(invoice, "client", None)
    invoice_no = _invoice_number(invoice)
    rows = []
    for index, item in enumerate(_invoice_items(invoice), start=1):
        desc = getattr(item, "description", None) or getattr(item, "item_description", None) or getattr(item, "service_name", None) or "Professional Fees"
        sac = getattr(item, "sac_code", None) or getattr(item, "hsn_sac", None) or ""
        taxable = getattr(item, "taxable_value", None) or getattr(item, "amount", None) or getattr(item, "line_total", None)
        gst_rate = getattr(item, "gst_rate", None) or getattr(item, "tax_rate", None) or ""
        total = getattr(item, "total_amount", None) or getattr(item, "gross_amount", None) or taxable
        rows.append(
            f"<tr><td>{index}</td><td>{html.escape(_safe_text(desc))}</td><td>{html.escape(_safe_text(sac))}</td>"
            f"<td style='text-align:right'>{html.escape(_money(taxable))}</td>"
            f"<td style='text-align:right'>{html.escape(_safe_text(gst_rate))}</td>"
            f"<td style='text-align:right'>{html.escape(_money(total))}</td></tr>"
        )
    if not rows:
        rows.append("<tr><td>1</td><td>Professional Fees</td><td></td><td style='text-align:right'></td><td></td><td style='text-align:right'></td></tr>")

    return f"""<!doctype html>
<html><head><meta charset='utf-8'><title>Invoice {html.escape(invoice_no)}</title>
<style>body{{font-family:Arial,sans-serif;color:#111827}}.box{{border:1px solid #d1d5db;border-radius:10px;padding:18px;max-width:900px;margin:0 auto}}table{{width:100%;border-collapse:collapse;margin-top:14px}}th,td{{border:1px solid #d1d5db;padding:8px;font-size:13px}}th{{background:#f3f4f6;text-align:left}}.right{{text-align:right}}.muted{{color:#6b7280}}</style></head>
<body><div class='box'>
<h2>Tax Invoice</h2>
<p><strong>{html.escape(firm_name or _safe_text(getattr(invoice, 'firm_name', '') or 'Audit Firm'))}</strong></p>
<p class='muted'>Invoice No: <strong>{html.escape(invoice_no)}</strong><br>Invoice Date: {html.escape(_safe_text(getattr(invoice, 'invoice_date', '')))}<br>Due Date: {html.escape(_safe_text(getattr(invoice, 'due_date', '')))}</p>
<h3>Bill To</h3><p>{html.escape(_safe_text(_client_name(client)))}</p>
<table><thead><tr><th>#</th><th>Description</th><th>SAC</th><th class='right'>Taxable</th><th class='right'>GST %</th><th class='right'>Total</th></tr></thead><tbody>{''.join(rows)}</tbody></table>
<table><tbody>
<tr><th>Taxable Value</th><td class='right'>{html.escape(_money(getattr(invoice, 'taxable_value', None) or getattr(invoice, 'subtotal', None)))}</td></tr>
<tr><th>CGST</th><td class='right'>{html.escape(_money(getattr(invoice, 'cgst_amount', None) or getattr(invoice, 'cgst', None)))}</td></tr>
<tr><th>SGST</th><td class='right'>{html.escape(_money(getattr(invoice, 'sgst_amount', None) or getattr(invoice, 'sgst', None)))}</td></tr>
<tr><th>IGST</th><td class='right'>{html.escape(_money(getattr(invoice, 'igst_amount', None) or getattr(invoice, 'igst', None)))}</td></tr>
<tr><th>Total</th><td class='right'><strong>{html.escape(_money(getattr(invoice, 'total_amount', None)))}</strong></td></tr>
<tr><th>Outstanding</th><td class='right'>{html.escape(_money(getattr(invoice, 'balance_amount', None)))}</td></tr>
</tbody></table>
<p class='muted'>This is an ERP-generated invoice attachment. For payment, please use the client portal payment link provided in the email.</p>
</div></body></html>"""


def build_receipt_html(payment: Any, *, firm_name: str = "") -> str:
    invoice = getattr(payment, "invoice", None)
    client = getattr(payment, "client", None) or getattr(invoice, "client", None)
    receipt_no = _safe_text(getattr(payment, "receipt_no", None) or getattr(payment, "receipt_number", None) or getattr(payment, "id", "receipt"))
    return f"""<!doctype html>
<html><head><meta charset='utf-8'><title>Receipt {html.escape(receipt_no)}</title>
<style>body{{font-family:Arial,sans-serif;color:#111827}}.box{{border:1px solid #d1d5db;border-radius:10px;padding:18px;max-width:760px;margin:0 auto}}table{{width:100%;border-collapse:collapse;margin-top:14px}}th,td{{border:1px solid #d1d5db;padding:8px;font-size:13px}}th{{background:#f3f4f6;text-align:left}}.right{{text-align:right}}.muted{{color:#6b7280}}</style></head>
<body><div class='box'>
<h2>Payment Receipt</h2>
<p><strong>{html.escape(firm_name or 'Audit Firm')}</strong></p>
<table><tbody>
<tr><th>Receipt No</th><td>{html.escape(receipt_no)}</td></tr>
<tr><th>Receipt Date</th><td>{html.escape(_safe_text(getattr(payment, 'payment_date', None) or getattr(payment, 'receipt_date', None)))}</td></tr>
<tr><th>Client</th><td>{html.escape(_safe_text(_client_name(client)))}</td></tr>
<tr><th>Invoice No</th><td>{html.escape(_invoice_number(invoice) if invoice else '')}</td></tr>
<tr><th>Amount Received</th><td class='right'><strong>{html.escape(_money(getattr(payment, 'amount_received', None) or getattr(payment, 'amount', None)))}</strong></td></tr>
<tr><th>TDS Deducted</th><td class='right'>{html.escape(_money(getattr(payment, 'tds_amount', None) or getattr(payment, 'tds_deducted', None)))}</td></tr>
<tr><th>Bank Charges</th><td class='right'>{html.escape(_money(getattr(payment, 'bank_charges', None)))}</td></tr>
<tr><th>Payment Mode</th><td>{html.escape(_safe_text(getattr(payment, 'mode', None) or getattr(payment, 'payment_mode', None)))}</td></tr>
<tr><th>Reference</th><td>{html.escape(_safe_text(getattr(payment, 'reference_no', None) or getattr(payment, 'reference_number', None) or getattr(payment, 'utr_no', None)))}</td></tr>
</tbody></table>
<p class='muted'>This is an ERP-generated receipt attachment.</p>
</div></body></html>"""


def invoice_attachment(invoice: Any, *, firm_name: str = "") -> EmailAttachment:
    invoice_no = _safe_filename(_invoice_number(invoice), "invoice")
    return EmailAttachment(
        filename=f"Invoice_{invoice_no}.html",
        content=build_invoice_html(invoice, firm_name=firm_name).encode("utf-8"),
        content_type="text/html",
    )


def receipt_attachment(payment: Any, *, firm_name: str = "") -> EmailAttachment:
    receipt_no = _safe_filename(_safe_text(getattr(payment, "receipt_no", None) or getattr(payment, "receipt_number", None) or getattr(payment, "id", "receipt")), "receipt")
    return EmailAttachment(
        filename=f"Receipt_{receipt_no}.html",
        content=build_receipt_html(payment, firm_name=firm_name).encode("utf-8"),
        content_type="text/html",
    )
