#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Hermes 分析師必須透過 OllamaService 三主機級聯。"""

import time
import inspect
from types import SimpleNamespace

import pytest

import services.ai_call_logger as logger_mod
import services.hermes_analyst_service as hermes_mod
from services.ai_call_logger import _reset_kill_switch


@pytest.fixture(autouse=True)
def reset_ai_logger(monkeypatch):
    _reset_kill_switch()
    captured = []

    def fake_write(state):
        captured.append({
            'caller': state.caller,
            'provider': state.provider,
            'model': state.model,
            'status': state.status,
            'fallback_to': state.fallback_to,
            'error': state.error,
            'meta': dict(state.meta),
        })

    monkeypatch.setattr(logger_mod, '_write_to_db', fake_write)
    monkeypatch.setenv('AI_CALL_LOGGING_ENABLED', 'true')
    yield captured


def _wait_for(captured, n=1, timeout=2.0):
    deadline = time.time() + timeout
    while time.time() < deadline:
        if len(captured) >= n:
            return True
        time.sleep(0.01)
    return False


def _stub_ollama(monkeypatch, *, content: str, host: str):
    fake_resp = SimpleNamespace(
        success=True,
        content=content,
        model=hermes_mod.HERMES_MODEL,
        error=None,
        total_duration=1.2,
        host=host,
        input_tokens=33,
        output_tokens=22,
    )

    class FakeOllamaService:
        instances = []

        def __init__(self, *args, **kwargs):
            self.init_args = args
            self.init_kwargs = kwargs
            self.generate_calls = []
            FakeOllamaService.instances.append(self)

        def generate(self, **kwargs):
            self.generate_calls.append(kwargs)
            return fake_resp

    monkeypatch.setattr(hermes_mod, 'OllamaService', FakeOllamaService)
    return FakeOllamaService


def test_hermes_intent_uses_ollama_service_and_logs_actual_host(monkeypatch, reset_ai_logger):
    fake_service = _stub_ollama(
        monkeypatch,
        content='{"intent":"query_sales","confidence":0.9,"complexity_score":0.8,'
                '"requires_data_fetch":true,"preliminary_answer":""}',
        host='http://34.21.145.224:11434',
    )

    svc = hermes_mod.HermesAnalystService()
    result = svc._call_hermes_intent("本週業績如何？")

    assert result['intent'] == 'query_sales'
    assert result['metadata']['source'] == 'hermes_llm'
    call_kwargs = fake_service.instances[0].generate_calls[0]
    assert call_kwargs['model'] == hermes_mod.HERMES_MODEL
    assert call_kwargs['keep_alive'] == hermes_mod.HERMES_KEEP_ALIVE
    assert call_kwargs['allow_111_fallback'] is False

    assert _wait_for(reset_ai_logger, 1)
    rec = reset_ai_logger[0]
    assert rec['caller'] == 'hermes_intent'
    assert rec['provider'] == 'ollama_secondary'
    assert rec['meta']['host_label'] == 'GCP-SSD-2'


def test_hermes_batch_analyze_uses_ollama_service_and_logs_secondary(monkeypatch, reset_ai_logger):
    fake_service = _stub_ollama(
        monkeypatch,
        content='[{"sku":"A1","name":"測試商品","category":"家電","momo_price":120,'
                '"pchome_price":100,"gap_pct":20,"sales_7d_delta_pct":-30,'
                '"risk":"HIGH","recommended_action":"建議人工評估","confidence":0.8}]',
        host='http://34.21.145.224:11434',
    )
    monkeypatch.setattr(hermes_mod, 'build_mcp_context', lambda *args, **kwargs: 'MCP context')

    candidates = [{
        'sku': 'A1',
        'name': '測試商品',
        'category': '家電',
        'momo_price': 120,
        'pchome_price': 100,
        'sales_7d_prev': 1000,
        'sales_7d_curr': 700,
        'competitor_tags': [
            'identity_v2',
            'match_type_same_product_different_pack',
            'price_basis_unit_price',
            'alert_tier_unit_price_review',
        ],
        'competitor_match_score': 0.74,
        'competitor_product_id': 'PCH-UNIT',
        'competitor_product_name': '測試商品 2入組',
    }]

    svc = hermes_mod.HermesAnalystService()
    raw_threats, items = svc._batch_analyze(candidates)

    assert raw_threats[0]['sku'] == 'A1'
    assert items[0]['gap_pct'] == 20.0
    assert items[0]['match_type'] == 'same_product_different_pack'
    assert items[0]['price_basis'] == 'unit_price'
    assert items[0]['alert_tier'] == 'unit_price_review'
    call_kwargs = fake_service.instances[0].generate_calls[0]
    assert call_kwargs['system_prompt'] == svc.SYSTEM_PROMPT
    assert call_kwargs['keep_alive'] == hermes_mod.HERMES_KEEP_ALIVE
    assert call_kwargs['allow_111_fallback'] is False

    assert _wait_for(reset_ai_logger, 1)
    rec = reset_ai_logger[0]
    assert rec['caller'] == 'hermes_analyst'
    assert rec['provider'] == 'ollama_secondary'
    assert rec['meta']['host_label'] == 'GCP-SSD-2'


def test_hermes_candidate_sql_only_joins_direct_price_alert_matches():
    sql_text = inspect.getsource(hermes_mod.HermesAnalystService.fetch_candidates)
    compact_sql = "".join(sql_text.split())

    assert '"match_type":"exact"' in compact_sql
    assert '"price_basis":"total_price"' in compact_sql
    assert '"alert_tier":"price_alert_exact"' in compact_sql
    assert "match_type_exact" in sql_text
    assert "price_basis_total_price" in sql_text
    assert "alert_tier_price_alert_exact" in sql_text


def test_hermes_keep_alive_defaults_to_short_runner_residency():
    assert hermes_mod.HERMES_KEEP_ALIVE == "5m"


def test_hermes_disables_111_fallback_by_default():
    assert hermes_mod.HERMES_ALLOW_111_FALLBACK is False
