"""
Tests for E-Mail-Template routes.
Pattern: app.dependency_overrides[get_db] for FastAPI DI.
"""

import uuid
import os
import sys
from datetime import datetime

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# Ensure backend dir is on path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from classroom_engine.database import Base, get_db
from compliance.db.email_template_models import (
    EmailTemplateDB, EmailTemplateVersionDB, EmailTemplateApprovalDB,
    EmailSendLogDB, EmailTemplateSettingsDB,
)
from compliance.api.email_template_routes import router as email_template_router

# In-memory SQLite for testing
SQLALCHEMY_DATABASE_URL = "sqlite:///./test_email_templates.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

TENANT_ID = "9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"
HEADERS = {"X-Tenant-ID": TENANT_ID}

app = FastAPI()
app.include_router(email_template_router, prefix="/api/compliance")


def override_get_db():
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()


app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)


@pytest.fixture(autouse=True)
def setup_db():
    """Create all tables before each test, drop after."""
    Base.metadata.create_all(bind=engine)
    yield
    Base.metadata.drop_all(bind=engine)


# =============================================================================
# Helper
# =============================================================================

def _create_template(template_type="welcome", name=None):
    """Create a template and return the response dict."""
    body = {"template_type": template_type}
    if name:
        body["name"] = name
    r = client.post("/api/compliance/email-templates", json=body, headers=HEADERS)
    assert r.status_code == 200, r.text
    return r.json()


def _create_version(template_id, subject="Test Betreff", body_html="<p>Hallo</p>"):
    """Create a version for a template and return the response dict."""
    r = client.post(
        f"/api/compliance/email-templates/{template_id}/versions",
        json={"subject": subject, "body_html": body_html, "version": "1.0"},
        headers=HEADERS,
    )
    assert r.status_code == 200, r.text
    return r.json()


# =============================================================================
# Template Types
# =============================================================================

class TestTemplateTypes:
    def test_get_types(self):
        r = client.get("/api/compliance/email-templates/types")
        assert r.status_code == 200
        types = r.json()
        assert len(types) == 20
        names = [t["type"] for t in types]
        assert "welcome" in names
        assert "dsr_receipt" in names
        assert "breach_notification_authority" in names

    def test_types_have_variables(self):
        r = client.get("/api/compliance/email-templates/types")
        types = r.json()
        welcome = [t for t in types if t["type"] == "welcome"][0]
        assert "user_name" in welcome["variables"]
        assert welcome["category"] == "general"


# =============================================================================
# Template CRUD
# =============================================================================

class TestCreateTemplate:
    def test_create_template(self):
        t = _create_template("welcome")
        assert t["template_type"] == "welcome"
        assert t["name"] == "Willkommen"
        assert t["category"] == "general"
        assert t["is_active"] is True
        assert "id" in t

    def test_create_with_custom_name(self):
        t = _create_template("welcome", name="Custom Name")
        assert t["name"] == "Custom Name"

    def test_create_duplicate_type(self):
        _create_template("welcome")
        r = client.post("/api/compliance/email-templates", json={"template_type": "welcome"}, headers=HEADERS)
        assert r.status_code == 409

    def test_create_unknown_type(self):
        r = client.post("/api/compliance/email-templates", json={"template_type": "nonexistent"}, headers=HEADERS)
        assert r.status_code == 400

    def test_create_with_description(self):
        r = client.post("/api/compliance/email-templates", json={
            "template_type": "dsr_receipt",
            "description": "DSR Eingangsbestaetigung Template",
        }, headers=HEADERS)
        assert r.status_code == 200
        assert r.json()["description"] == "DSR Eingangsbestaetigung Template"


class TestListTemplates:
    def test_list_empty(self):
        r = client.get("/api/compliance/email-templates", headers=HEADERS)
        assert r.status_code == 200
        assert r.json() == []

    def test_list_templates(self):
        _create_template("welcome")
        _create_template("dsr_receipt")
        r = client.get("/api/compliance/email-templates", headers=HEADERS)
        assert r.status_code == 200
        assert len(r.json()) == 2

    def test_list_by_category(self):
        _create_template("welcome")  # general
        _create_template("dsr_receipt")  # dsr
        r = client.get("/api/compliance/email-templates?category=dsr", headers=HEADERS)
        assert r.status_code == 200
        data = r.json()
        assert len(data) == 1
        assert data[0]["category"] == "dsr"

    def test_list_with_latest_version(self):
        t = _create_template("welcome")
        _create_version(t["id"], subject="Version 1")
        r = client.get("/api/compliance/email-templates", headers=HEADERS)
        data = r.json()
        assert data[0]["latest_version"] is not None
        assert data[0]["latest_version"]["subject"] == "Version 1"


class TestGetTemplate:
    def test_get_template(self):
        t = _create_template("welcome")
        r = client.get(f"/api/compliance/email-templates/{t['id']}", headers=HEADERS)
        assert r.status_code == 200
        assert r.json()["template_type"] == "welcome"

    def test_get_not_found(self):
        fake_id = str(uuid.uuid4())
        r = client.get(f"/api/compliance/email-templates/{fake_id}", headers=HEADERS)
        assert r.status_code == 404

    def test_get_invalid_id(self):
        r = client.get("/api/compliance/email-templates/not-a-uuid", headers=HEADERS)
        assert r.status_code == 400


# =============================================================================
# Default Content
# =============================================================================

class TestDefaultContent:
    def test_get_default_content(self):
        r = client.get("/api/compliance/email-templates/default/welcome")
        assert r.status_code == 200
        data = r.json()
        assert data["template_type"] == "welcome"
        assert "variables" in data
        assert "default_subject" in data
        assert "default_body_html" in data

    def test_get_default_unknown_type(self):
        r = client.get("/api/compliance/email-templates/default/nonexistent")
        assert r.status_code == 404


# =============================================================================
# Initialize Defaults
# =============================================================================

class TestInitialize:
    def test_initialize_defaults(self):
        r = client.post("/api/compliance/email-templates/initialize", headers=HEADERS)
        assert r.status_code == 200
        data = r.json()
        assert data["count"] == 20

    def test_initialize_idempotent(self):
        client.post("/api/compliance/email-templates/initialize", headers=HEADERS)
        r = client.post("/api/compliance/email-templates/initialize", headers=HEADERS)
        assert r.status_code == 200
        assert "already initialized" in r.json()["message"]


# =============================================================================
# Version Management
# =============================================================================

class TestVersionCreate:
    def test_create_version_via_path(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        assert v["subject"] == "Test Betreff"
        assert v["status"] == "draft"
        assert v["template_id"] == t["id"]

    def test_create_version_via_query(self):
        t = _create_template("welcome")
        r = client.post(
            f"/api/compliance/email-templates/versions?template_id={t['id']}",
            json={"subject": "Query-Version", "body_html": "<p>Test</p>"},
            headers=HEADERS,
        )
        assert r.status_code == 200
        assert r.json()["subject"] == "Query-Version"

    def test_create_version_template_not_found(self):
        fake_id = str(uuid.uuid4())
        r = client.post(
            f"/api/compliance/email-templates/{fake_id}/versions",
            json={"subject": "S", "body_html": "<p>B</p>"},
            headers=HEADERS,
        )
        assert r.status_code == 404


class TestVersionGet:
    def test_get_versions(self):
        t = _create_template("welcome")
        _create_version(t["id"], subject="V1")
        _create_version(t["id"], subject="V2")
        r = client.get(f"/api/compliance/email-templates/{t['id']}/versions", headers=HEADERS)
        assert r.status_code == 200
        data = r.json()
        assert len(data) == 2

    def test_get_version_detail(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        r = client.get(f"/api/compliance/email-templates/versions/{v['id']}")
        assert r.status_code == 200
        assert r.json()["subject"] == "Test Betreff"

    def test_get_version_not_found(self):
        r = client.get(f"/api/compliance/email-templates/versions/{uuid.uuid4()}")
        assert r.status_code == 404


class TestVersionUpdate:
    def test_update_draft(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        r = client.put(
            f"/api/compliance/email-templates/versions/{v['id']}",
            json={"subject": "Updated Subject", "body_html": "<p>Neu</p>"},
        )
        assert r.status_code == 200
        assert r.json()["subject"] == "Updated Subject"

    def test_update_non_draft_fails(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        # Submit to review
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        # Try to update
        r = client.put(
            f"/api/compliance/email-templates/versions/{v['id']}",
            json={"subject": "Should Fail"},
        )
        assert r.status_code == 400


# =============================================================================
# Approval Workflow
# =============================================================================

class TestWorkflow:
    def test_submit_for_review(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        assert r.status_code == 200
        assert r.json()["status"] == "review"
        assert r.json()["submitted_at"] is not None

    def test_approve_version(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/approve")
        assert r.status_code == 200
        assert r.json()["status"] == "approved"

    def test_reject_version(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/reject")
        assert r.status_code == 200
        assert r.json()["status"] == "draft"  # back to draft

    def test_publish_version(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/approve")
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/publish")
        assert r.status_code == 200
        assert r.json()["status"] == "published"
        assert r.json()["published_at"] is not None

    def test_publish_draft_directly(self):
        """Publishing from draft is allowed (shortcut for admins)."""
        t = _create_template("welcome")
        v = _create_version(t["id"])
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/publish")
        assert r.status_code == 200
        assert r.json()["status"] == "published"

    def test_submit_non_draft_fails(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/submit")
        assert r.status_code == 400

    def test_approve_non_review_fails(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        r = client.post(f"/api/compliance/email-templates/versions/{v['id']}/approve")
        assert r.status_code == 400

    def test_full_workflow(self):
        """Full cycle: create → submit → approve → publish."""
        t = _create_template("welcome")
        v = _create_version(t["id"], subject="Workflow Test")
        vid = v["id"]

        # Draft
        assert v["status"] == "draft"

        # Submit
        r = client.post(f"/api/compliance/email-templates/versions/{vid}/submit")
        assert r.json()["status"] == "review"

        # Approve
        r = client.post(f"/api/compliance/email-templates/versions/{vid}/approve")
        assert r.json()["status"] == "approved"

        # Publish
        r = client.post(f"/api/compliance/email-templates/versions/{vid}/publish")
        assert r.json()["status"] == "published"


# =============================================================================
# Preview & Send Test
# =============================================================================

class TestPreview:
    def test_preview_with_variables(self):
        t = _create_template("welcome")
        v = _create_version(t["id"], subject="Hallo {{user_name}}", body_html="<p>Willkommen {{user_name}} bei {{company_name}}</p>")
        r = client.post(
            f"/api/compliance/email-templates/versions/{v['id']}/preview",
            json={"variables": {"user_name": "Max", "company_name": "ACME"}},
        )
        assert r.status_code == 200
        data = r.json()
        assert data["subject"] == "Hallo Max"
        assert "Willkommen Max bei ACME" in data["body_html"]

    def test_preview_with_defaults(self):
        t = _create_template("welcome")
        v = _create_version(t["id"], subject="Hi {{user_name}}", body_html="<p>{{company_name}}</p>")
        r = client.post(
            f"/api/compliance/email-templates/versions/{v['id']}/preview",
            json={},
        )
        assert r.status_code == 200
        data = r.json()
        # Default placeholders
        assert "[user_name]" in data["subject"]

    def test_preview_not_found(self):
        r = client.post(
            f"/api/compliance/email-templates/versions/{uuid.uuid4()}/preview",
            json={},
        )
        assert r.status_code == 404


class TestSendTest:
    def test_send_test_email(self):
        t = _create_template("welcome")
        v = _create_version(t["id"], subject="Test {{user_name}}")
        r = client.post(
            f"/api/compliance/email-templates/versions/{v['id']}/send-test",
            json={"recipient": "test@example.de", "variables": {"user_name": "Max"}},
            headers=HEADERS,
        )
        assert r.status_code == 200
        data = r.json()
        assert data["success"] is True
        assert "test@example.de" in data["message"]

    def test_send_test_creates_log(self):
        t = _create_template("welcome")
        v = _create_version(t["id"], subject="Log Test")
        client.post(
            f"/api/compliance/email-templates/versions/{v['id']}/send-test",
            json={"recipient": "log@example.de"},
            headers=HEADERS,
        )
        # Check logs
        r = client.get("/api/compliance/email-templates/logs", headers=HEADERS)
        assert r.status_code == 200
        logs = r.json()["logs"]
        assert len(logs) == 1
        assert logs[0]["recipient"] == "log@example.de"
        assert logs[0]["status"] == "test_sent"


# =============================================================================
# Settings
# =============================================================================

class TestSettings:
    def test_get_default_settings(self):
        r = client.get("/api/compliance/email-templates/settings", headers=HEADERS)
        assert r.status_code == 200
        data = r.json()
        assert data["sender_name"] == "Datenschutzbeauftragter"
        assert data["primary_color"] == "#4F46E5"

    def test_update_settings(self):
        r = client.put(
            "/api/compliance/email-templates/settings",
            json={"sender_name": "DSB Max", "company_name": "ACME GmbH", "primary_color": "#FF0000"},
            headers=HEADERS,
        )
        assert r.status_code == 200
        data = r.json()
        assert data["sender_name"] == "DSB Max"
        assert data["company_name"] == "ACME GmbH"
        assert data["primary_color"] == "#FF0000"

    def test_update_settings_partial(self):
        # First create
        client.put(
            "/api/compliance/email-templates/settings",
            json={"sender_name": "DSB", "company_name": "Test"},
            headers=HEADERS,
        )
        # Then partial update
        r = client.put(
            "/api/compliance/email-templates/settings",
            json={"company_name": "Neue Firma"},
            headers=HEADERS,
        )
        assert r.status_code == 200
        data = r.json()
        assert data["sender_name"] == "DSB"  # unchanged
        assert data["company_name"] == "Neue Firma"


# =============================================================================
# Logs
# =============================================================================

class TestLogs:
    def test_logs_empty(self):
        r = client.get("/api/compliance/email-templates/logs", headers=HEADERS)
        assert r.status_code == 200
        assert r.json()["logs"] == []
        assert r.json()["total"] == 0

    def test_logs_pagination(self):
        # Create some logs via send-test
        t = _create_template("welcome")
        v = _create_version(t["id"], subject="Pagination")
        for i in range(5):
            client.post(
                f"/api/compliance/email-templates/versions/{v['id']}/send-test",
                json={"recipient": f"user{i}@example.de"},
                headers=HEADERS,
            )
        r = client.get("/api/compliance/email-templates/logs?limit=2&offset=0", headers=HEADERS)
        data = r.json()
        assert data["total"] == 5
        assert len(data["logs"]) == 2

    def test_logs_filter_by_type(self):
        t1 = _create_template("welcome")
        t2 = _create_template("dsr_receipt")
        v1 = _create_version(t1["id"], subject="W")
        v2 = _create_version(t2["id"], subject="D")
        client.post(
            f"/api/compliance/email-templates/versions/{v1['id']}/send-test",
            json={"recipient": "a@b.de"}, headers=HEADERS,
        )
        client.post(
            f"/api/compliance/email-templates/versions/{v2['id']}/send-test",
            json={"recipient": "c@d.de"}, headers=HEADERS,
        )
        r = client.get("/api/compliance/email-templates/logs?template_type=dsr_receipt", headers=HEADERS)
        data = r.json()
        assert data["total"] == 1
        assert data["logs"][0]["template_type"] == "dsr_receipt"


# =============================================================================
# Stats
# =============================================================================

class TestStats:
    def test_stats_empty(self):
        r = client.get("/api/compliance/email-templates/stats", headers=HEADERS)
        assert r.status_code == 200
        data = r.json()
        assert data["total"] == 0
        assert data["active"] == 0
        assert data["published"] == 0
        assert data["total_sent"] == 0

    def test_stats_with_data(self):
        t = _create_template("welcome")
        v = _create_version(t["id"])
        # Publish the version
        client.post(f"/api/compliance/email-templates/versions/{v['id']}/publish")
        # Send a test
        client.post(
            f"/api/compliance/email-templates/versions/{v['id']}/send-test",
            json={"recipient": "stats@test.de"}, headers=HEADERS,
        )
        r = client.get("/api/compliance/email-templates/stats", headers=HEADERS)
        data = r.json()
        assert data["total"] == 1
        assert data["active"] == 1
        assert data["published"] == 1
        assert data["total_sent"] == 1
        assert data["by_category"]["general"] == 1
