"""
server.py — Flask HTTP service wrapping compose_hero + fill_template.

Endpoint: POST /generate
Config (env vars):
    OUTPUT_BASE_DIR  base directory for generated files (default: ./output)
    FLASK_PORT       port to listen on (default: 5001)

Run:
    python server.py
    gunicorn -w 2 -b 0.0.0.0:5001 'server:create_app()'
"""
from __future__ import annotations

import copy
import os
import pathlib
import urllib.request

from flask import Flask, jsonify, request

from compose_hero import compose_hero
from fill_template import fill_template

# Template HTML files — resolved relative to this file's location
_SCRIPT_DIR = pathlib.Path(__file__).parent
_TEMPLATE_DIR = _SCRIPT_DIR.parent / "emails templates" / "Loyalty"
_TEMPLATES = {
    "fr": _TEMPLATE_DIR / "template_FR.html",
    "nl": _TEMPLATE_DIR / "template_NL.html",
}

# Required top-level POST body fields
_REQUIRED_FIELDS = (
    "brief",
    "selected_title_fr",
    "selected_title_nl",
    "background_type",
    "campaign_slug",
)


def create_app(config: dict | None = None) -> Flask:
    app = Flask(__name__)

    # Defaults
    app.config["OUTPUT_BASE_DIR"] = os.environ.get("OUTPUT_BASE_DIR", "./output")

    if config:
        app.config.update(config)

    @app.get("/health")
    def health():
        return jsonify({"status": "ok"})

    @app.post("/generate")
    def generate():
        # ── Parse JSON body ──────────────────────────────────────────────────
        if not request.is_json:
            return jsonify({"error": "Request must be application/json"}), 400

        body = request.get_json(silent=True)
        if body is None:
            return jsonify({"error": "Invalid or empty JSON body"}), 400

        # ── Validate required fields ─────────────────────────────────────────
        missing = [f for f in _REQUIRED_FIELDS if f not in body]
        if missing:
            return jsonify({"error": f"Missing required fields: {missing}"}), 400

        # ── Build brief (deep-copy to avoid mutating the caller's object) ────
        brief = copy.deepcopy(body["brief"])

        selected_title_fr: str = body["selected_title_fr"]
        selected_title_nl: str = body["selected_title_nl"]
        background_type: str = body["background_type"]
        background_color: str = body.get("background_color", "#000000")
        poster_fit: str = body.get("poster_fit", "full")
        background_image_path: str | None = body.get("background_image_path")
        campaign_slug: str = body["campaign_slug"]

        # Inject Pierre's choices into the brief
        brief["fr"]["hero_title"] = selected_title_fr
        brief["nl"]["hero_title"] = selected_title_nl
        brief["background_type"] = background_type
        brief["background_color"] = background_color
        brief["poster_fit"] = poster_fit
        if background_image_path:
            brief["background_image_path"] = background_image_path

        # ── Resolve output directory ─────────────────────────────────────────
        out_dir = pathlib.Path(app.config["OUTPUT_BASE_DIR"]) / campaign_slug
        out_dir.mkdir(parents=True, exist_ok=True)

        # ── Download poster if URL provided instead of local path ────────────
        poster_url: str | None = body.get("poster_url")
        if poster_url and not brief.get("poster_path"):
            poster_path = str(out_dir / "poster.jpg")
            dl_req = urllib.request.Request(
                poster_url,
                headers={"User-Agent": "Mozilla/5.0 (compatible; ProximusBot/1.0)"},
            )
            with urllib.request.urlopen(dl_req) as resp, open(poster_path, "wb") as f:
                f.write(resp.read())
            brief["poster_path"] = poster_path

        results: dict[str, str] = {}

        # ── Generate FR + NL ─────────────────────────────────────────────────
        for lang in ("fr", "nl"):
            hero_filename = f"hero_{lang.upper()}.jpg"
            hero_path = str(out_dir / hero_filename)

            compose_hero(brief, lang=lang, output_path=hero_path)

            # hero_image_src is relative so previewing HTML in a browser works
            brief[lang]["hero_image_src"] = hero_filename

            template_html = _TEMPLATES[lang].read_text(encoding="utf-8")
            filled_html = fill_template(template_html, brief, lang=lang)

            email_path = out_dir / f"email_{lang.upper()}.html"
            email_path.write_text(filled_html, encoding="utf-8")

            results[f"hero_{lang}"] = hero_path
            results[f"email_{lang}"] = str(email_path)

        return jsonify(results), 200

    return app


if __name__ == "__main__":
    port = int(os.environ.get("FLASK_PORT", 5001))
    create_app().run(host="0.0.0.0", port=port)
