"""应用 2：财务洞察。

8 个时间维度独立调用，每次调用结果写入 ai_cache，
同时创建 ai_conversations + ai_messages 记录。

营业日分界点：每日 08:00（BUSINESS_DAY_START_HOUR 环境变量，默认 8）。

app_id = "app2_finance"
"""

from __future__ import annotations

import json
import logging
import os
from datetime import date, datetime, timedelta

from app.ai.dashscope_client import DashScopeClient
from app.ai.cache_service import AICacheService
from app.ai.conversation_service import ConversationService
from app.ai.prompts.app2_finance_prompt import build_prompt
from app.ai.schemas import CacheTypeEnum

logger = logging.getLogger(__name__)

APP_ID = "app2_finance"

# 8 个时间维度编码
TIME_DIMENSIONS = (
    "this_month",
    "last_month",
    "this_week",
    "last_week",
    "last_3_months",
    "this_quarter",
    "last_quarter",
    "last_6_months",
)


def get_business_date() -> date:
    """根据营业日分界点计算当前营业日。

    分界点前（如 07:59）视为前一天营业日，
    分界点及之后（如 08:00）视为当天营业日。
    """
    hour = int(os.environ.get("BUSINESS_DAY_START_HOUR", "8"))
    now = datetime.now()
    if now.hour < hour:
        return (now - timedelta(days=1)).date()
    return now.date()


def compute_time_range(dimension: str, business_date: date) -> tuple[date, date]:
    """计算时间维度对应的日期范围 [start, end]（闭区间）。

    Args:
        dimension: 时间维度编码
        business_date: 当前营业日

    Returns:
        (start_date, end_date) 元组
    """
    y, m, d = business_date.year, business_date.month, business_date.day

    if dimension == "this_month":
        start = date(y, m, 1)
        return start, business_date

    if dimension == "last_month":
        prev = _month_offset(y, m, -1)
        start = date(prev[0], prev[1], 1)
        end = date(y, m, 1) - timedelta(days=1)
        return start, end

    if dimension == "this_week":
        # 周一起算
        weekday = business_date.weekday()  # 0=周一
        start = business_date - timedelta(days=weekday)
        return start, business_date

    if dimension == "last_week":
        weekday = business_date.weekday()
        this_monday = business_date - timedelta(days=weekday)
        last_monday = this_monday - timedelta(days=7)
        last_sunday = this_monday - timedelta(days=1)
        return last_monday, last_sunday

    if dimension == "last_3_months":
        # 当前月 - 3 ~ 当前月 - 1
        end_ym = _month_offset(y, m, -1)
        start_ym = _month_offset(y, m, -3)
        start = date(start_ym[0], start_ym[1], 1)
        # end = 上月最后一天
        end = date(y, m, 1) - timedelta(days=1)
        return start, end

    if dimension == "this_quarter":
        q_start_month = ((m - 1) // 3) * 3 + 1
        start = date(y, q_start_month, 1)
        return start, business_date

    if dimension == "last_quarter":
        q_start_month = ((m - 1) // 3) * 3 + 1
        # 上季度结束 = 本季度第一天 - 1
        this_q_start = date(y, q_start_month, 1)
        end = this_q_start - timedelta(days=1)
        # 上季度开始
        ly, lm = end.year, end.month
        lq_start_month = ((lm - 1) // 3) * 3 + 1
        start = date(ly, lq_start_month, 1)
        return start, end

    if dimension == "last_6_months":
        # 当前月 - 6 ~ 当前月 - 1
        end_ym = _month_offset(y, m, -1)
        start_ym = _month_offset(y, m, -6)
        start = date(start_ym[0], start_ym[1], 1)
        end = date(y, m, 1) - timedelta(days=1)
        return start, end

    raise ValueError(f"未知时间维度: {dimension}")


async def run(
    context: dict,
    client: DashScopeClient,
    cache_svc: AICacheService,
    conv_svc: ConversationService,
) -> dict:
    """执行 App2 财务洞察调用。

    Args:
        context: 包含 site_id, time_dimension, user_id(默认'system'), nickname(默认'')
        bailian: 百炼客户端
        cache_svc: 缓存服务
        conv_svc: 对话服务

    Returns:
        百炼返回的结构化 JSON（insights 数组）
    """
    site_id = context["site_id"]
    time_dimension = context["time_dimension"]
    user_id = context.get("user_id", "system")
    nickname = context.get("nickname", "")

    # 构建 Prompt
    prompt_context = {
        "site_id": site_id,
        "time_dimension": time_dimension,
        "current_data": context.get("current_data", {}),
        "previous_data": context.get("previous_data", {}),
    }
    messages = build_prompt(prompt_context)

    # 创建对话记录
    conversation_id = conv_svc.create_conversation(
        user_id=user_id,
        nickname=nickname,
        app_id=APP_ID,
        site_id=site_id,
        source_context={"time_dimension": time_dimension},
    )

    # 写入 system prompt 消息
    conv_svc.add_message(
        conversation_id=conversation_id,
        role="system",
        content=messages[0]["content"],
    )
    # 写入 user 消息
    conv_svc.add_message(
        conversation_id=conversation_id,
        role="user",
        content=messages[1]["content"],
    )

    # 调用百炼 API
    result, tokens_used = await bailian.chat_json(messages)

    # 写入 assistant 消息
    conv_svc.add_message(
        conversation_id=conversation_id,
        role="assistant",
        content=json.dumps(result, ensure_ascii=False),
        tokens_used=tokens_used,
    )

    # 写入缓存
    cache_svc.write_cache(
        cache_type=CacheTypeEnum.APP2_FINANCE.value,
        site_id=site_id,
        target_id=time_dimension,
        result_json=result,
        triggered_by=f"user:{user_id}",
    )

    logger.info(
        "App2 财务洞察完成: site_id=%s dimension=%s conversation_id=%s tokens=%d",
        site_id, time_dimension, conversation_id, tokens_used,
    )

    return result


def _month_offset(year: int, month: int, offset: int) -> tuple[int, int]:
    """计算月份偏移，返回 (year, month)。"""
    # 转为 0-based 计算
    total = (year * 12 + (month - 1)) + offset
    return total // 12, total % 12 + 1
