from datetime import datetime

from jinja2 import BaseLoader, Environment, StrictUndefined, TemplateError


DEFAULT_PAYMENT_METHODS = [
    "bank_transfer",
    "cash",
    "credit_card",
]


AVAILABLE_TEMPLATE_VARIABLES = [
    "company_name",
    "invoice_number",
    "invoice_date",
    "due_date",
    "customer_name",
    "customer_contact_name",
    "customer_email",
    "customer_phone",
    "customer_mobile",
    "customer_address",
    "currency",
    "subtotal",
    "total_tax",
    "total_amount",
    "notes",
    "issued_at",
    "payment_methods",
    "payment_methods_text",
    "items",
]

DEFAULT_INVOICE_EMAIL_SUBJECT_TEMPLATE = "Invoice {{ invoice_number }}"

DEFAULT_INVOICE_EMAIL_BODY_TEMPLATE = """Hello {{ customer_name }},

Please find attached invoice {{ invoice_number }}.

Invoice date: {{ invoice_date }}
Due date: {{ due_date }}
Amount due: {{ currency }} {{ total_amount }}

{% if notes %}Notes:
{{ notes }}

{% endif %}Regards,
{{ company_name }}"""


DEFAULT_INVOICE_TEMPLATE = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-size: 14px; color: #1e293b; padding: 40px; }
  .invoice-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 40px; }
  .company-name { font-size: 24px; font-weight: 700; color: #4f46e5; }
  .invoice-title { font-size: 28px; font-weight: 700; }
  .invoice-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 30px; }
  .meta-block { padding: 16px; background: #f8fafc; border-radius: 8px; }
  .meta-label { font-size: 11px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px; }
  .meta-value { font-size: 14px; }
  .items-table { width: 100%; border-collapse: collapse; margin-bottom: 24px; }
  .items-table th { text-align: left; padding: 12px 16px; font-size: 11px; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; border-bottom: 2px solid #e2e8f0; }
  .items-table th.right { text-align: right; }
  .items-table td { padding: 12px 16px; border-bottom: 1px solid #e2e8f0; }
  .items-table td.right { text-align: right; }
  .totals { display: flex; justify-content: flex-end; }
  .totals-table { width: 300px; }
  .totals-row { display: flex; justify-content: space-between; padding: 8px 0; }
  .totals-row.grand { font-size: 18px; font-weight: 700; border-top: 2px solid #4f46e5; color: #4f46e5; margin-top: 8px; padding-top: 12px; }
  .notes { margin-top: 28px; padding: 16px; background: #f8fafc; border-radius: 8px; }
  .payment-methods { margin-top: 28px; }
  .payment-methods ul { margin: 8px 0 0 20px; }
  .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #e2e8f0; font-size: 12px; color: #64748b; text-align: center; }
</style>
</head>
<body>
<div class="invoice-header">
  <div>
    <div class="company-name">{{ company_name }}</div>
    <div style="font-size:13px;color:#64748b;margin-top:4px;">Invoice</div>
  </div>
  <div style="text-align:right;">
    <div class="invoice-title">INVOICE</div>
    <div style="font-size:14px;font-weight:600;margin-top:8px;font-family:monospace;">{{ invoice_number }}</div>
  </div>
</div>
<div class="invoice-meta">
  <div class="meta-block"><div class="meta-label">Invoice Date</div><div class="meta-value">{{ invoice_date }}</div></div>
  <div class="meta-block"><div class="meta-label">Due Date</div><div class="meta-value">{{ due_date }}</div></div>
  <div class="meta-block">
    <div class="meta-label">Bill To</div>
    <div class="meta-value">{{ customer_name }}</div>
    {% if customer_contact_name %}<div style="font-size:12px;color:#64748b;">{{ customer_contact_name }}</div>{% endif %}
    {% if customer_email %}<div style="font-size:12px;color:#64748b;">{{ customer_email }}</div>{% endif %}
    {% if customer_phone %}<div style="font-size:12px;color:#64748b;">{{ customer_phone }}</div>{% endif %}
    {% if customer_mobile %}<div style="font-size:12px;color:#64748b;">{{ customer_mobile }}</div>{% endif %}
    {% if customer_address %}<div style="font-size:12px;color:#64748b;white-space:pre-line;">{{ customer_address }}</div>{% endif %}
  </div>
  <div class="meta-block">
    <div class="meta-label">Amount Due</div>
    <div class="meta-value" style="font-size:20px;font-weight:700;color:#4f46e5;">{{ currency }} {{ total_amount }}</div>
  </div>
</div>
<table class="items-table">
  <thead>
    <tr>
      <th>Description</th>
      <th class="right">Qty</th>
      <th class="right">Unit Price</th>
      <th class="right">Tax</th>
      <th class="right">Subtotal</th>
      <th class="right">Total</th>
    </tr>
  </thead>
  <tbody>
    {% for item in items %}
    <tr>
      <td>{{ item.description }}</td>
      <td class="right">{{ item.quantity }}</td>
      <td class="right">{{ currency }} {{ item.unit_price }}</td>
      <td class="right">{{ item.tax_rate_percent }}</td>
      <td class="right">{{ currency }} {{ item.subtotal }}</td>
      <td class="right">{{ currency }} {{ item.total }}</td>
    </tr>
    {% endfor %}
  </tbody>
</table>
<div class="totals">
  <div class="totals-table">
    <div class="totals-row"><span>Subtotal</span><span>{{ currency }} {{ subtotal }}</span></div>
    <div class="totals-row"><span>GST</span><span>{{ currency }} {{ total_tax }}</span></div>
    <div class="totals-row grand"><span>Total</span><span>{{ currency }} {{ total_amount }}</span></div>
  </div>
</div>
{% if notes %}
<div class="notes">
  <div class="meta-label">Notes</div>
  <div style="white-space:pre-line;">{{ notes }}</div>
</div>
{% endif %}
<div class="payment-methods">
  <div class="meta-label">Payment Methods</div>
  <ul>
    {% for method in payment_methods %}
    <li>{{ method }}</li>
    {% endfor %}
  </ul>
</div>
<div class="footer"><p>Generated on {{ issued_at }}</p></div>
</body>
</html>"""


def _format_money(value) -> str:
    return f"{float(value or 0):.2f}"


def _load_payment_methods(db) -> list[str]:
    from app.core.models import SystemConfig

    row = db.get(SystemConfig, "invoice_payment_methods")
    raw = row.key_value if row and row.key_value else ",".join(DEFAULT_PAYMENT_METHODS)
    parts = [part.strip() for chunk in raw.splitlines() for part in chunk.split(",")]
    methods = [part for part in parts if part]
    return methods or list(DEFAULT_PAYMENT_METHODS)


def _load_template_source(db) -> str:
    from app.core.models import SystemConfig

    row = db.get(SystemConfig, "invoice_template_html")
    if row and row.key_value and row.key_value.strip():
        return row.key_value
    return DEFAULT_INVOICE_TEMPLATE


def _load_email_subject_template(db) -> str:
    from app.core.models import SystemConfig

    row = db.get(SystemConfig, "invoice_email_subject_template")
    if row and row.key_value and row.key_value.strip():
        return row.key_value
    return DEFAULT_INVOICE_EMAIL_SUBJECT_TEMPLATE


def _load_email_body_template(db) -> str:
    from app.core.models import SystemConfig

    row = db.get(SystemConfig, "invoice_email_body_template")
    if row and row.key_value and row.key_value.strip():
        return row.key_value
    return DEFAULT_INVOICE_EMAIL_BODY_TEMPLATE


def _build_context(invoice, items, customer, payment_methods: list[str]) -> dict:
    primary_contact_name = getattr(customer, "contact_name", "") if customer else ""
    customer_name = getattr(customer, "company_name", "") or getattr(customer, "name", "") or "Unknown"

    normalized_items = []
    for item in items:
        normalized_items.append(
            {
                "description": item.description or "Item",
                "quantity": f"{float(item.quantity or 0):.2f}",
                "unit_price": _format_money(item.unit_price),
                "tax_rate": f"{float(item.tax_rate or 0):.4f}",
                "tax_rate_percent": f"{float(item.tax_rate or 0) * 100:.1f}%",
                "subtotal": _format_money(item.subtotal),
                "total": _format_money(item.total),
            }
        )

    return {
        "company_name": "ERP System",
        "invoice": invoice,
        "customer": customer,
        "items": normalized_items,
        "invoice_number": invoice.invoice_number,
        "invoice_date": str(invoice.invoice_date),
        "due_date": str(invoice.due_date or "Upon receipt"),
        "customer_name": customer_name,
        "customer_contact_name": primary_contact_name,
        "customer_email": getattr(customer, "email", "") if customer else "",
        "customer_phone": getattr(customer, "phone", "") if customer else "",
        "customer_mobile": getattr(customer, "mobile", "") if customer else "",
        "customer_address": getattr(customer, "address", "") if customer else "",
        "currency": invoice.currency,
        "subtotal": _format_money(invoice.subtotal),
        "total_tax": _format_money(invoice.total_tax),
        "total_amount": _format_money(invoice.total_amount),
        "notes": invoice.notes or "",
        "issued_at": datetime.now().strftime("%Y-%m-%d"),
        "payment_methods": payment_methods,
        "payment_methods_text": ", ".join(payment_methods),
    }


def render_invoice_html(db, invoice, items, customer) -> str:
    template_source = _load_template_source(db)
    payment_methods = _load_payment_methods(db)
    context = _build_context(invoice, items, customer, payment_methods)
    environment = Environment(
        loader=BaseLoader(),
        autoescape=True,
        undefined=StrictUndefined,
    )
    try:
        template = environment.from_string(template_source)
        return template.render(**context)
    except TemplateError as exc:
        raise ValueError(f"Invoice template error: {exc}") from exc


def render_invoice_email(db, invoice, items, customer) -> tuple[str, str]:
    payment_methods = _load_payment_methods(db)
    context = _build_context(invoice, items, customer, payment_methods)
    environment = Environment(
        loader=BaseLoader(),
        autoescape=False,
        undefined=StrictUndefined,
        trim_blocks=True,
        lstrip_blocks=True,
    )
    try:
        subject_template = environment.from_string(_load_email_subject_template(db))
        body_template = environment.from_string(_load_email_body_template(db))
        subject = subject_template.render(**context).strip()
        body = body_template.render(**context).strip()
        return subject, body
    except TemplateError as exc:
        raise ValueError(f"Invoice email template error: {exc}") from exc


def generate_invoice_pdf(db, invoice_id: int) -> bytes:
    """Generate PDF bytes for an invoice with a configurable HTML template."""
    try:
        from weasyprint import HTML
    except (ImportError, OSError) as exc:
        raise ImportError(
            "WeasyPrint not available: missing system libraries. "
            "Install with: apt-get install libpango-1.0-0 libpangocairo-1.0-0 "
            "libgobject-2.0-0 libcairo2 fonts-dejavu"
        ) from exc

    from app.core.models import Customer, Invoice, InvoiceItem

    invoice = db.query(Invoice).get(invoice_id)
    if not invoice:
        raise ValueError("Invoice not found")

    items = db.query(InvoiceItem).filter(InvoiceItem.invoice_id == invoice_id).all()
    customer = db.query(Customer).get(invoice.customer_id)

    html = render_invoice_html(db, invoice, items, customer)
    return HTML(string=html).write_pdf()
