"""Six-dimension analyzer with scoring."""

from collections import Counter, defaultdict
from typing import List, Dict, Any

import numpy as np

from .models import Conversation, DimensionResult, CheckupResult
from .classifier import classify_all
from .rules import SCORING_BREAKPOINTS, DIMENSIONS


def piecewise_score(value: float, breakpoints: list) -> float:
    """Piecewise linear mapping from raw value to 0-100 score."""
    if value <= breakpoints[0][0]:
        return breakpoints[0][1]
    if value >= breakpoints[-1][0]:
        return breakpoints[-1][1]

    for i in range(len(breakpoints) - 1):
        x0, y0 = breakpoints[i]
        x1, y1 = breakpoints[i + 1]
        if x0 <= value <= x1:
            t = (value - x0) / (x1 - x0) if x1 != x0 else 0
            return y0 + t * (y1 - y0)

    return breakpoints[-1][1]


def analyze(conversations: List[Conversation]) -> CheckupResult:
    """Run full six-dimension analysis on conversations."""
    classifications = classify_all(conversations)

    # Group conversations by week
    by_week: Dict[str, List[Conversation]] = defaultdict(list)
    for conv in conversations:
        week = conv.week
        if week:
            by_week[week].append(conv)

    weeks = sorted(by_week.keys())
    if not weeks:
        return _empty_result(conversations)

    # Analyze each dimension
    q_result = _analyze_questioning(conversations, classifications, by_week, weeks)
    j_result = _analyze_judgment(conversations, classifications, by_week, weeks)
    h_result = _analyze_hands_on(conversations, classifications, by_week, weeks)
    d_result = _analyze_deep_thinking(conversations, classifications, by_week, weeks)
    e_result = _analyze_execution(conversations, by_week, weeks)
    n_result = _analyze_narrative(conversations, classifications, by_week, weeks)

    dimensions = {
        "questioning": q_result,
        "judgment": j_result,
        "hands_on": h_result,
        "deep_thinking": d_result,
        "execution": e_result,
        "narrative": n_result,
    }

    insights = _generate_insights(dimensions)
    period = f"{weeks[0]} ~ {weeks[-1]}" if weeks else ""
    platform = conversations[0].platform if conversations else ""

    # Raw analysis data for JSON export
    raw = _build_raw_analysis(conversations, classifications, by_week, weeks)

    return CheckupResult(
        dimensions=dimensions,
        total_conversations=len(conversations),
        weeks=weeks,
        period=period,
        insights=insights,
        platform=platform,
        raw_analysis=raw,
    )


def _analyze_questioning(convs, cls, by_week, weeks) -> DimensionResult:
    """Questioning: ratio of high-level questions (L2+L3+L4)."""
    weekly_data = {}
    total_dist = Counter()

    for week in weeks:
        counts = Counter()
        for conv in by_week[week]:
            level = cls[conv.id]["question_level"]
            counts[level] += 1
            total_dist[level] += 1

        total = sum(counts.values())
        high = counts["L2_What"] + counts["L3_Why"] + counts["L4_Meta"]
        weekly_data[week] = high / total if total > 0 else 0

    raw_value = float(np.mean(list(weekly_data.values()))) if weekly_data else 0
    score = piecewise_score(raw_value, SCORING_BREAKPOINTS["questioning"])

    return DimensionResult(
        name=DIMENSIONS["questioning"]["name"],
        name_en=DIMENSIONS["questioning"]["name_en"],
        score=round(score, 1),
        raw_value=round(raw_value, 4),
        weekly_data=weekly_data,
        description="高阶问题(L2+L3+L4)占比",
    )


def _analyze_judgment(convs, cls, by_week, weeks) -> DimensionResult:
    """Judgment: ratio of conversations with judgment signals."""
    weekly_data = {}

    for week in weeks:
        total = len(by_week[week])
        with_judgment = sum(1 for c in by_week[week] if cls[c.id]["has_judgment"])
        weekly_data[week] = with_judgment / total if total > 0 else 0

    raw_value = float(np.mean(list(weekly_data.values()))) if weekly_data else 0
    score = piecewise_score(raw_value, SCORING_BREAKPOINTS["judgment"])

    return DimensionResult(
        name=DIMENSIONS["judgment"]["name"],
        name_en=DIMENSIONS["judgment"]["name_en"],
        score=round(score, 1),
        raw_value=round(raw_value, 4),
        weekly_data=weekly_data,
        description="含判断信号的会话占比",
    )


def _analyze_hands_on(convs, cls, by_week, weeks) -> DimensionResult:
    """Hands-on: output keyword ratio + message intensity composite."""
    weekly_data = {}

    for week in weeks:
        total = len(by_week[week])
        output_count = sum(1 for c in by_week[week] if cls[c.id]["has_output"])
        weekly_data[week] = output_count / total if total > 0 else 0

    raw_value = float(np.mean(list(weekly_data.values()))) if weekly_data else 0
    score = piecewise_score(raw_value, SCORING_BREAKPOINTS["hands_on"])

    return DimensionResult(
        name=DIMENSIONS["hands_on"]["name"],
        name_en=DIMENSIONS["hands_on"]["name_en"],
        score=round(score, 1),
        raw_value=round(raw_value, 4),
        weekly_data=weekly_data,
        description="输出型会话占比",
    )


def _analyze_deep_thinking(convs, cls, by_week, weeks) -> DimensionResult:
    """Deep thinking: L3_Why + reflection signals ratio."""
    weekly_data = {}

    for week in weeks:
        total = len(by_week[week])
        deep_count = 0
        for conv in by_week[week]:
            c = cls[conv.id]
            if c["question_level"] == "L3_Why" or c["has_deep_thinking"]:
                deep_count += 1
        weekly_data[week] = deep_count / total if total > 0 else 0

    raw_value = float(np.mean(list(weekly_data.values()))) if weekly_data else 0
    score = piecewise_score(raw_value, SCORING_BREAKPOINTS["deep_thinking"])

    return DimensionResult(
        name=DIMENSIONS["deep_thinking"]["name"],
        name_en=DIMENSIONS["deep_thinking"]["name_en"],
        score=round(score, 1),
        raw_value=round(raw_value, 4),
        weekly_data=weekly_data,
        description="L3思维+反思型会话占比",
    )


def _analyze_execution(convs, by_week, weeks) -> DimensionResult:
    """Execution: active days per week (consistency)."""
    weekly_data = {}

    for week in weeks:
        active_days = set()
        for conv in by_week[week]:
            ds = conv.date_str
            if ds:
                active_days.add(ds)
        weekly_data[week] = float(len(active_days))

    raw_value = float(np.mean(list(weekly_data.values()))) if weekly_data else 0
    score = piecewise_score(raw_value, SCORING_BREAKPOINTS["execution"])

    return DimensionResult(
        name=DIMENSIONS["execution"]["name"],
        name_en=DIMENSIONS["execution"]["name_en"],
        score=round(score, 1),
        raw_value=round(raw_value, 4),
        weekly_data=weekly_data,
        description="每周活跃天数",
    )


def _analyze_narrative(convs, cls, by_week, weeks) -> DimensionResult:
    """Narrative: writing/narrative conversation ratio."""
    weekly_data = {}

    for week in weeks:
        total = len(by_week[week])
        narrative_count = sum(1 for c in by_week[week] if cls[c.id]["has_narrative"])
        weekly_data[week] = narrative_count / total if total > 0 else 0

    raw_value = float(np.mean(list(weekly_data.values()))) if weekly_data else 0
    score = piecewise_score(raw_value, SCORING_BREAKPOINTS["narrative"])

    return DimensionResult(
        name=DIMENSIONS["narrative"]["name"],
        name_en=DIMENSIONS["narrative"]["name_en"],
        score=round(score, 1),
        raw_value=round(raw_value, 4),
        weekly_data=weekly_data,
        description="写作/叙事型会话占比",
    )


def _generate_insights(dimensions: Dict[str, DimensionResult]) -> List[str]:
    """Auto-generate insights based on scores."""
    insights = []
    d = dimensions

    if d["hands_on"].raw_value > 0.6:
        insights.append("动手力突出：大部分会话都在产出实际成果，执行力强")
    if d["questioning"].raw_value < 0.2:
        insights.append(
            "提问力空间：高阶问题占比较低，大部分交互停留在执行层(L1_How)，"
            "可尝试在开始会话前先问自己\"我真正想解决的问题是什么\""
        )
    if d["judgment"].raw_value > 0.3:
        insights.append("判断力活跃：较多会话中展现了主动判断和方向设定")
    if d["judgment"].raw_value < 0.15:
        insights.append("判断力空间：较少主动评价/否定 AI 输出，可能在\"接受\"模式居多")
    if d["deep_thinking"].raw_value < 0.1:
        insights.append("深思力盲区：极少反思型会话，建议每周安排一次\"复盘会话\"")
    if d["narrative"].raw_value > 0.1:
        insights.append("叙事力有实践：有一定比例的写作型会话，说明在将经验转化为表达")
    if d["execution"].raw_value >= 5:
        insights.append("践行力稳定：几乎每天都在使用，习惯已形成")

    if not insights:
        insights.append("数据量较少，建议积累更多对话后再分析以获得更准确的洞察")

    return insights


def _build_raw_analysis(convs, cls, by_week, weeks) -> Dict:
    """Build raw analysis data for JSON export."""
    # Question level distribution
    q_dist = Counter()
    q_weekly = {}
    for week in weeks:
        wc = Counter()
        for conv in by_week[week]:
            level = cls[conv.id]["question_level"]
            wc[level] += 1
            q_dist[level] += 1
        q_weekly[week] = dict(wc)

    # Judgment type distribution
    j_types = Counter()
    for conv in convs:
        for jt in cls[conv.id]["judgment_types"]:
            j_types[jt] += 1

    return {
        "question_distribution": dict(q_dist),
        "question_weekly": q_weekly,
        "judgment_types": dict(j_types),
    }


def _empty_result(conversations) -> CheckupResult:
    empty_dim = DimensionResult(
        name="", name_en="", score=0, raw_value=0,
        weekly_data={}, description="",
    )
    return CheckupResult(
        dimensions={k: DimensionResult(
            name=v["name"], name_en=v["name_en"], score=0, raw_value=0,
            weekly_data={}, description="",
        ) for k, v in DIMENSIONS.items()},
        total_conversations=len(conversations),
        weeks=[],
        period="",
        insights=["无法分析：没有带日期的对话数据"],
        platform="",
    )
