import asyncio
import os
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import AsyncMock

import pytest
from fastapi import HTTPException
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

os.environ.setdefault("JWT_SECRET", "test-jwt-secret-value-with-32-chars")

from app.api import ai as ai_api
from app.api import telegram as telegram_api
from app.core.config import get_smtp_config
from app.core.database import Base
from app.core.models import CustomerContact, SystemConfig, Tenant


def make_db():
    engine = create_engine("sqlite:///:memory:")
    Base.metadata.create_all(engine)
    db = sessionmaker(bind=engine)()
    db.add_all([
        Tenant(id=1, company_code="alpha", name="Alpha"),
        Tenant(id=2, company_code="beta", name="Beta"),
    ])
    db.commit()
    return db


def test_smtp_config_is_read_from_the_requested_tenant():
    db = make_db()
    db.add_all([
        SystemConfig(tenant_id=1, key_name="smtp_host", key_value="alpha.smtp.test"),
        SystemConfig(tenant_id=2, key_name="smtp_host", key_value="beta.smtp.test"),
    ])
    db.commit()

    assert get_smtp_config(db, 2)["host"] == "beta.smtp.test"


def test_ai_customer_contacts_receive_the_customer_tenant_id():
    db = make_db()
    _, action, customer_id = ai_api._create_customer(
        db,
        {"name": "Beta Customer", "contacts": [{"name": "Billing"}]},
        tenant_id=2,
    )

    assert action == "create_customer"
    assert db.query(CustomerContact).filter_by(customer_id=customer_id).one().tenant_id == 2


@pytest.mark.asyncio
async def test_telegram_webhook_rejects_missing_secret(monkeypatch):
    db = make_db()
    db.add_all([
        SystemConfig(tenant_id=2, key_name="telegram_chat_id", key_value="222"),
        SystemConfig(tenant_id=2, key_name="telegram_webhook_secret", key_value="beta-secret", is_secret=True),
    ])
    db.commit()
    monkeypatch.setattr(telegram_api, "send_telegram_message", AsyncMock(return_value={"success": True}))

    with pytest.raises(HTTPException) as exc:
        await telegram_api.telegram_webhook(
            {"message": {"chat": {"id": 222}, "text": "show invoices"}}, db=db
        )

    assert exc.value.status_code == 403


@pytest.mark.asyncio
async def test_telegram_webhook_rejects_unknown_secret(monkeypatch):
    db = make_db()
    db.add_all([
        SystemConfig(tenant_id=2, key_name="telegram_chat_id", key_value="222"),
        SystemConfig(tenant_id=2, key_name="telegram_webhook_secret", key_value="beta-secret", is_secret=True),
    ])
    db.commit()
    monkeypatch.setattr(telegram_api, "send_telegram_message", AsyncMock(return_value={"success": True}))

    with pytest.raises(HTTPException) as exc:
        await telegram_api.telegram_webhook(
            {"message": {"chat": {"id": 222}, "text": "show invoices"}},
            x_telegram_bot_api_secret_token="wrong-secret",
            db=db,
        )

    assert exc.value.status_code == 403


@pytest.mark.asyncio
async def test_telegram_webhook_resolves_tenant_from_its_configured_chat(monkeypatch):
    db = make_db()
    db.add_all([
        SystemConfig(tenant_id=1, key_name="telegram_chat_id", key_value="111"),
        SystemConfig(tenant_id=1, key_name="telegram_webhook_secret", key_value="alpha-secret", is_secret=True),
        SystemConfig(tenant_id=2, key_name="telegram_chat_id", key_value="222"),
        SystemConfig(tenant_id=2, key_name="telegram_webhook_secret", key_value="beta-secret", is_secret=True),
    ])
    db.commit()
    seen_tenants = []

    async def fake_ai_handler(db, message, context=None, tenant_id=None):
        seen_tenants.append(tenant_id)
        return telegram_api.ChatResponse(reply="ok")

    monkeypatch.setattr(telegram_api, "handle_ai_chat_message", fake_ai_handler)
    monkeypatch.setattr(telegram_api, "send_telegram_message", AsyncMock(return_value={"success": True}))

    result = await telegram_api.telegram_webhook(
        {"message": {"chat": {"id": 222}, "text": "show invoices"}},
        x_telegram_bot_api_secret_token="beta-secret",
        db=db,
    )

    assert result["handled"] == "ai_chat"
    assert seen_tenants == [2]


@pytest.mark.asyncio
async def test_update_webhook_url_creates_and_registers_tenant_secret(monkeypatch):
    db = make_db()
    captured = {}

    async def fake_set_webhook(url, **kwargs):
        captured.update(kwargs)
        return {"success": True}

    monkeypatch.setattr(telegram_api, "set_telegram_webhook", fake_set_webhook)

    await telegram_api.update_webhook_url(
        telegram_api.TelegramWebhookUpdate(url="https://erp.example/api/telegram/webhook"),
        current_user=SimpleNamespace(tenant_id=2),
        db=db,
    )

    row = db.query(SystemConfig).filter_by(
        tenant_id=2,
        key_name="telegram_webhook_secret",
    ).one()
    assert row.is_secret is True
    assert len(row.key_value) >= 32
    assert captured["secret_token"] == row.key_value


def test_all_reviewed_write_routes_use_permissions_and_mcp_has_company_code():
    root = Path(__file__).resolve().parents[2]
    for path, permission in {
        "backend/app/api/products.py": "products.write",
        "backend/app/api/subscriptions.py": "subscriptions.write",
        "backend/app/api/employees.py": "employees.write",
        "backend/app/api/payroll.py": "payroll.write",
        "backend/app/api/telegram.py": "settings.write",
    }.items():
        assert f'require_permission("{permission}")' in (root / path).read_text(encoding="utf-8")

    mcp = (root / "erp_mcp.py").read_text(encoding="utf-8")
    assert "ERP_COMPANY_CODE" in mcp
    assert '"company_code": ERP_COMPANY_CODE' in mcp
    assert "ERP_COMPANY_CODE=your-erp-company-code" in mcp
    assert "ERP_USERNAME / ERP_PASSWORD / ERP_COMPANY_CODE 配置" in mcp
