"""
WhatsApp Template Registry
--------------------------
Single source of truth for ALL approved Meta WhatsApp templates.

How to add a new template:
1.  Get the template approved in Meta Business Manager.
2.  Add an entry under TEMPLATES with:
      - meta_name      : exact name as it appears in Meta
      - language_code  : he / he_IL / en / en_US …
      - friendly_name  : shown in the frontend dropdown
      - description    : optional, for documentation
      - header_type    : "TEXT" or "IMAGE" or "VIDEO" or "DOCUMENT" (default: "TEXT")
      - header_params  : ordered list of variable keys sent in the HEADER component
                         (empty list [] if the template has no header variables)
      - header_handle  : media handle for IMAGE/VIDEO/DOCUMENT headers (optional)
      - body_params    : ordered list of variable keys sent in the BODY component
      - button_type    : "URL" or "PHONE_NUMBER" or "QUICK_REPLY" (optional)
      - button_text    : button label/text (optional)
      - button_url     : button URL (optional, for URL buttons)
      - fallbacks      : dict {key: default_string} used when the caller doesn't
                         provide a value for that key

The backend will:
  - Look up the template by its registry key (e.g. "wedding_invitation")
  - Build the Meta payload header/body param lists in exact declaration order
  - Apply fallbacks for any missing keys
  - Validate total param count == len(header_params) + len(body_params)

IMPORTANT: param order in header_params / body_params MUST match the
           {{1}}, {{2}}, … placeholder order inside the Meta template.
"""

import json
import os
from typing import Dict, Any, Optional
from sqlalchemy.orm import Session


def load_custom_templates(db: Session) -> Dict[str, Dict[str, Any]]:
    """Load user-created templates from the database."""
    from models import WhatsAppTemplate
    
    try:
        templates = db.query(WhatsAppTemplate).all()
        result = {}
        for t in templates:
            result[t.template_key] = {
                "meta_name": t.meta_name,
                "language_code": t.language_code,
                "friendly_name": t.friendly_name,
                "description": t.description,
                "header_type": t.header_type,
                "header_text": t.header_text,
                "header_handle": t.header_handle,
                "body_text": t.body_text,
                "header_params": json.loads(t.header_params),
                "body_params": json.loads(t.body_params),
                "button_type": t.button_type,
                "button_text": t.button_text,
                "button_url": t.button_url,
                "button_param_key": t.button_url,  # backward compat
                "fallbacks": json.loads(t.fallbacks),
                "guest_name_key": "",
            }
        return result
    except Exception as e:
        print(f"[WARNING] Failed to load custom templates from database: {e}")
        return {}


def save_custom_templates(db: Session, data: Dict[str, Dict[str, Any]]) -> None:
    """Persist custom templates to the database."""
    from models import WhatsAppTemplate
    
    try:
        # Clear old templates
        db.query(WhatsAppTemplate).delete()
        
        # Add new ones
        for key, tpl in data.items():
            template_record = WhatsAppTemplate(
                template_key=key,
                meta_name=tpl.get("meta_name", key),
                friendly_name=tpl.get("friendly_name", key),
                language_code=tpl.get("language_code", "he"),
                description=tpl.get("description", ""),
                header_type=tpl.get("header_type", "TEXT"),
                header_text=tpl.get("header_text", ""),
                header_handle=tpl.get("header_handle", ""),
                body_text=tpl.get("body_text", ""),
                header_params=json.dumps(tpl.get("header_params", [])),
                body_params=json.dumps(tpl.get("body_params", [])),
                button_type=tpl.get("button_type", ""),
                button_text=tpl.get("button_text", ""),
                button_url=tpl.get("button_url", ""),
                fallbacks=json.dumps(tpl.get("fallbacks", {})),
            )
            db.add(template_record)
        
        db.commit()
    except Exception as e:
        print(f"[WARNING] Failed to save custom templates to database: {e}")
        db.rollback()


def get_all_templates(db: Session) -> Dict[str, Dict[str, Any]]:
    """Return merged dict: built-in TEMPLATES + user custom templates."""
    merged = dict(TEMPLATES)
    custom = load_custom_templates(db)
    merged.update(custom)
    
    # Debug logging
    import logging
    logger = logging.getLogger(__name__)
    if custom:
        logger.info(f"[Templates] Loaded {len(custom)} custom templates from database: {list(custom.keys())}")
    logger.debug(f"[Templates] All available templates: {list(merged.keys())}")
    
    return merged


def add_custom_template(db: Session, key: str, template: Dict[str, Any]) -> None:
    """Add or overwrite a custom template (cannot replace built-ins)."""
    if key in TEMPLATES:
        raise ValueError(f"Template key '{key}' is a built-in and cannot be overwritten.")
    data = load_custom_templates(db)
    data[key] = template
    save_custom_templates(db, data)


def delete_custom_template(db: Session, key: str) -> None:
    """Delete a custom template by key. Raises KeyError if not found."""
    if key in TEMPLATES:
        raise ValueError(f"Template key '{key}' is a built-in and cannot be deleted.")
    data = load_custom_templates(db)
    if key not in data:
        raise KeyError(f"Custom template '{key}' not found.")
    del data[key]
    save_custom_templates(db, data)


# ── Template registry ─────────────────────────────────────────────────────────

TEMPLATES: Dict[str, Dict[str, Any]] = {

    # ── wedding_invitation ────────────────────────────────────────────────────
    # Approved Hebrew wedding invitation template.
    # Header {{1}}  = guest name (greeting)
    # Body  {{1}}   = guest name  (same, repeated inside body)
    # Body  {{2}}   = groom name
    # Body  {{3}}   = bride name
    # Body  {{4}}   = venue / hall name
    # Body  {{5}}   = event date  (DD/MM)
    # Body  {{6}}   = event time  (HH:mm)
    # Body  {{7}}   = RSVP / guest link URL
    "wedding_invitation": {
        "meta_name": "wedding_invitation",
        "language_code": "he",
        "friendly_name": "הזמנה לחתונה",
        "description": "הזמנה רשמית לאירוע חתונה עם כל פרטי האירוע וקישור RSVP",
        "header_params": ["contact_name"],          # 1 header variable
        "body_params": [                             # 7 body variables
            "contact_name",    # body {{1}}
            "groom_name",      # body {{2}}
            "bride_name",      # body {{3}}
            "venue",           # body {{4}}
            "event_date",      # body {{5}}
            "event_time",      # body {{6}}
            "guest_link",      # body {{7}}
        ],
        "fallbacks": {
            "contact_name": "חבר",
            "groom_name":   "החתן",
            "bride_name":   "הכלה",
            "venue":        "האולם",
            "event_date":   "—",
            "event_time":   "—",
            "guest_link":   "https://invy.dvirlabs.com/guest",
        },
    },

    # ── save_the_date ─────────────────────────────────────────────────────────
    # Shorter "save the date" template — no venue/time details.
    # Create & approve this template in Meta before using it.
    # Header {{1}} = guest name
    # Body  {{1}}  = guest name  (repeated)
    # Body  {{2}}  = groom name
    # Body  {{3}}  = bride name
    # Body  {{4}}  = event date  (DD/MM/YYYY)
    # Body  {{5}}  = guest link
    "save_the_date": {
        "meta_name": "save_the_date",
        "language_code": "he",
        "friendly_name": "שמור את התאריך",
        "description": "הודעת 'שמור את התאריך' קצרה לפני ההזמנה הרשמית",
        "header_params": ["contact_name"],
        "body_params": [
            "contact_name",
            "groom_name",
            "bride_name",
            "event_date",
            "guest_link",
        ],
        "fallbacks": {
            "contact_name": "חבר",
            "groom_name":   "החתן",
            "bride_name":   "הכלה",
            "event_date":   "—",
            "guest_link":   "https://invy.dvirlabs.com/guest",
        },
    },

    # ── reminder_1 ────────────────────────────────────────────────────────────
    # Reminder template sent ~1 week before the event.
    # Header {{1}} = guest name
    # Body  {{1}}  = guest name
    # Body  {{2}}  = event date  (DD/MM)
    # Body  {{3}}  = event time  (HH:mm)
    # Body  {{4}}  = venue
    # Body  {{5}}  = guest link
    "reminder_1": {
        "meta_name": "reminder_1",
        "language_code": "he",
        "friendly_name": "תזכורת לאירוע",
        "description": "תזכורת שתשלח שבוע לפני האירוע",
        "header_params": ["contact_name"],
        "body_params": [
            "contact_name",
            "event_date",
            "event_time",
            "venue",
            "guest_link",
        ],
        "fallbacks": {
            "contact_name": "חבר",
            "event_date":   "—",
            "event_time":   "—",
            "venue":        "האולם",
            "guest_link":   "https://invy.dvirlabs.com/guest",
        },
    },
}


# ── Helper functions ──────────────────────────────────────────────────────────

def get_template(db: Session, key: str) -> Dict[str, Any]:
    """
    Return the template definition for *key* (checks both built-in + custom).
    Raises KeyError with a helpful message if not found.
    """
    all_tpls = get_all_templates(db)
    if key not in all_tpls:
        available = ", ".join(all_tpls.keys())
        raise KeyError(
            f"Unknown template key '{key}'. "
            f"Available templates: {available}"
        )
    return all_tpls[key]


def list_templates_for_frontend(db: Session) -> list:
    """
    Return a list suitable for the frontend dropdown (built-in + custom).
    Each item: {key, friendly_name, meta_name, param_count, language_code, description, is_custom}
    """
    all_tpls = get_all_templates(db)
    custom_keys = set(load_custom_templates(db).keys())
    return [
        {
            "key": key,
            "friendly_name": tpl["friendly_name"],
            "meta_name": tpl["meta_name"],
            "language_code": tpl["language_code"],
            "description": tpl.get("description", ""),
            "param_count": len(tpl["header_params"]) + len(tpl["body_params"]),
            "header_param_count": len(tpl["header_params"]),
            "body_param_count": len(tpl["body_params"]),
            "is_custom": key in custom_keys,
            "body_params": tpl["body_params"],
            "header_params": tpl["header_params"],
            "body_text": tpl.get("body_text", ""),
            "header_text": tpl.get("header_text", ""),
            "header_type": tpl.get("header_type", "TEXT"),
            "header_handle": tpl.get("header_handle", ""),
            "button_type": tpl.get("button_type", ""),
            "button_text": tpl.get("button_text", ""),
            "button_url": tpl.get("button_url", ""),
            "button_param_key": tpl.get("button_param_key", ""),
            "guest_name_key": tpl.get("guest_name_key", ""),
            "url_button": tpl.get("url_button", None),
        }
        for key, tpl in all_tpls.items()
    ]


def build_params_list(db: Session, key: str, values: dict) -> tuple:
    """
    Given a template key and a dict of {param_key: value}, return
    (header_params_list, body_params_list) after applying fallbacks.

    Both lists contain plain string values in correct order.
    """
    tpl = get_template(db, key)  # checks built-in + custom
    fallbacks = tpl.get("fallbacks", {})

    def resolve(param_key: str) -> str:
        raw = values.get(param_key, "")
        val = str(raw).strip() if raw else ""
        if not val:
            val = str(fallbacks.get(param_key, "—")).strip()
        return val

    header_values = [resolve(k) for k in tpl["header_params"]]
    body_values   = [resolve(k) for k in tpl["body_params"]]
    return header_values, body_values
