from __future__ import annotations

import json
from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy import stats


ROOT = Path(__file__).resolve().parent
FIG = ROOT / "figures"
FIG.mkdir(exist_ok=True)
plt.rcParams["font.family"] = ["Microsoft JhengHei", "Noto Sans CJK TC", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
RNG = np.random.default_rng(20260713)


def bootstrap_mean_difference(a: pd.Series, b: pd.Series, draws: int = 10_000) -> tuple[float, float]:
    """Percentile interval for integrated minus traditional mean."""
    av = a.dropna().to_numpy(dtype=float)
    bv = b.dropna().to_numpy(dtype=float)
    diffs = np.empty(draws)
    for i in range(draws):
        diffs[i] = RNG.choice(av, len(av), replace=True).mean() - RNG.choice(bv, len(bv), replace=True).mean()
    return float(np.quantile(diffs, 0.025)), float(np.quantile(diffs, 0.975))


def compare_groups(frame: pd.DataFrame, column: str) -> dict[str, float | int]:
    integrated = frame.loc[frame["group"] == "integrated", column]
    traditional = frame.loc[frame["group"] == "traditional", column]
    u = stats.mannwhitneyu(integrated, traditional, alternative="two-sided")
    ci_low, ci_high = bootstrap_mean_difference(integrated, traditional)
    return {
        "integrated_n": int(integrated.size),
        "traditional_n": int(traditional.size),
        "integrated_mean": float(integrated.mean()),
        "traditional_mean": float(traditional.mean()),
        "mean_difference": float(integrated.mean() - traditional.mean()),
        "mean_difference_bootstrap_ci95_low": ci_low,
        "mean_difference_bootstrap_ci95_high": ci_high,
        "mann_whitney_u": float(u.statistic),
        "mann_whitney_p": float(u.pvalue),
    }


df = pd.read_csv(ROOT / "cases-coded-60.csv")
audit = pd.read_csv(ROOT / "crawl-audit-120.csv")

index_columns = [
    "platform_leverage_index",
    "owned_asset_index",
    "differentiation_index",
    "public_channel_concentration_index",
]

summary = (
    df.groupby("group")[index_columns]
    .agg(["count", "mean", "median", "std"])
    .round(3)
)
summary.to_csv(ROOT / "group-index-summary.csv", encoding="utf-8-sig")

comparisons = {column: compare_groups(df, column) for column in index_columns}

rho_platform_owned_assets = stats.spearmanr(df["platform_leverage_index"], df["owned_asset_index"])
rho_platform_diff = stats.spearmanr(df["platform_leverage_index"], df["differentiation_index"])

strategy_order = ["low_public_digital_footprint", "direct_first", "platform_first", "orchestrated_hybrid"]
strategy_labels = {
    "low_public_digital_footprint": "Low public digital footprint",
    "direct_first": "Direct-first",
    "platform_first": "Platform-first",
    "orchestrated_hybrid": "Orchestrated hybrid",
}
strategy_table = pd.crosstab(df["group"], df["strategy_type"]).reindex(
    index=["traditional", "integrated"], columns=strategy_order, fill_value=0
)
strategy_table.to_csv(ROOT / "strategy-crosstab.csv", encoding="utf-8-sig")

signals = [
    "marketplace_signal",
    "social_signal",
    "line_signal",
    "payment_signal",
    "logistics_signal",
    "membership_signal",
    "direct_checkout_signal",
    "subscription_signal",
    "owned_content_signal",
]
signal_summary = df.groupby("group")[signals].agg(["sum", "mean"])
signal_summary.to_csv(ROOT / "capability-signal-summary.csv", encoding="utf-8-sig")

# Sensitivity: higher-confidence A/B public sources only.
high_conf = df[df["source_grade"].isin(["A", "B"])].copy()
sensitivity = {column: compare_groups(high_conf, column) for column in index_columns}

# Qualitative maximum-variation set: strongest documented case in each observed
# group × strategy cell, ranked by source grade then differentiation and owned assets.
rank_grade = {"A": 3, "B": 2, "C": 1}
df["source_rank"] = df["source_grade"].map(rank_grade).fillna(0)
qualitative = (
    df.sort_values(
        ["source_rank", "differentiation_index", "owned_asset_index", "platform_leverage_index"],
        ascending=False,
    )
    .groupby(["group", "strategy_type"], as_index=False)
    .head(2)
    .sort_values(["strategy_type", "group", "id"])
)
qualitative_columns = [
    "id",
    "group",
    "operator",
    "brand",
    "strategy_type",
    "platform_leverage_index",
    "owned_asset_index",
    "differentiation_index",
    "public_channel_concentration_index",
    "source_grade",
    "primary_url",
    "secondary_url",
]
qualitative[qualitative_columns].to_csv(ROOT / "qualitative-cases.csv", index=False, encoding="utf-8-sig")

# Figure 1: capability profiles.
plot_cols = ["platform_leverage_index", "owned_asset_index", "differentiation_index", "public_channel_concentration_index"]
plot_labels = ["Platform leverage", "Owned assets", "Differentiation", "Public-channel concentration"]
means = df.groupby("group")[plot_cols].mean().reindex(["traditional", "integrated"])
x = np.arange(len(plot_cols))
width = 0.36
fig, ax = plt.subplots(figsize=(9.5, 5.6))
ax.bar(x - width / 2, means.loc["traditional"], width, label="Traditional rice retailers", color="#bd8b4d")
ax.bar(x + width / 2, means.loc["integrated"], width, label="Integrated rice enterprises", color="#315c4c")
ax.set_xticks(x, plot_labels)
ax.set_ylim(0, 100)
ax.set_ylabel("Index (0–100)")
ax.set_title("Observed capability profiles in the fixed 60-case sample")
ax.legend(frameon=False)
ax.grid(axis="y", alpha=0.2)
fig.tight_layout()
fig.savefig(FIG / "capability-profile.png", dpi=190)
plt.close(fig)

# Figure 2: platform leverage × owned assets, with data-derived medians.
colors = {"traditional": "#bd8b4d", "integrated": "#315c4c"}
fig, ax = plt.subplots(figsize=(8.8, 6.2))
for group, part in df.groupby("group"):
    ax.scatter(
        part["platform_leverage_index"],
        part["owned_asset_index"],
        s=52,
        alpha=0.74,
        color=colors[group],
        edgecolor="white",
        linewidth=0.5,
        label="Traditional" if group == "traditional" else "Integrated",
    )
ax.axvline(df["platform_leverage_index"].median(), color="#777", linestyle="--", linewidth=1)
ax.axhline(df["owned_asset_index"].median(), color="#777", linestyle="--", linewidth=1)
ax.set_xlim(-4, 104)
ax.set_ylim(-4, 104)
ax.set_xlabel("Platform leverage index")
ax.set_ylabel("Owned digital asset index")
ax.set_title("Borrowed infrastructure and owned conversion assets")
ax.text(4, 96, "Direct-first", va="top", fontsize=9)
ax.text(96, 96, "Orchestrated hybrid", ha="right", va="top", fontsize=9)
ax.text(4, 3, "Low public digital footprint", va="bottom", fontsize=9)
ax.text(96, 3, "Platform-first", ha="right", va="bottom", fontsize=9)
ax.legend(frameon=False, loc="lower left", bbox_to_anchor=(0, 1.01), ncol=2)
ax.grid(alpha=0.16)
fig.tight_layout()
fig.savefig(FIG / "platform-owned-quadrants.png", dpi=190)
plt.close(fig)

# Figure 3: strategy counts by original sampling stratum.
fig, ax = plt.subplots(figsize=(9.5, 5.4))
bottom = np.zeros(2)
palette = ["#9f9a8f", "#6b8e76", "#b26a4a", "#294f44"]
for strategy, color in zip(strategy_order, palette):
    values = strategy_table[strategy].to_numpy()
    ax.bar([0, 1], values, bottom=bottom, label=strategy_labels[strategy], color=color)
    bottom += values
ax.set_xticks([0, 1], ["Traditional rice retailers", "Integrated rice enterprises"])
ax.set_ylabel("Cases")
ax.set_title("Data-derived strategy types in the 60-case sample")
ax.legend(frameon=False, bbox_to_anchor=(1.02, 1), loc="upper left")
ax.grid(axis="y", alpha=0.18)
fig.tight_layout()
fig.savefig(FIG / "strategy-types.png", dpi=190)
plt.close(fig)

# Figure 4: selected observable signals.
signal_labels = {
    "marketplace_signal": "Marketplace",
    "social_signal": "Social media",
    "line_signal": "LINE/contact",
    "payment_signal": "Online payment",
    "logistics_signal": "Delivery/logistics",
    "membership_signal": "Membership",
    "direct_checkout_signal": "Direct checkout",
    "subscription_signal": "Subscription",
    "owned_content_signal": "Owned content",
}
signal_shares = df.groupby("group")[signals].mean().reindex(["traditional", "integrated"]) * 100
y = np.arange(len(signals))
fig, ax = plt.subplots(figsize=(9.4, 6.0))
ax.barh(y - width / 2, signal_shares.loc["traditional"], height=width, color="#bd8b4d", label="Traditional")
ax.barh(y + width / 2, signal_shares.loc["integrated"], height=width, color="#315c4c", label="Integrated")
ax.set_yticks(y, [signal_labels[s] for s in signals])
ax.invert_yaxis()
ax.set_xlim(0, 100)
ax.set_xlabel("Cases with publicly observable signal (%)")
ax.set_title("Publicly observable platform and owned-asset signals")
ax.legend(frameon=False)
ax.grid(axis="x", alpha=0.2)
fig.tight_layout()
fig.savefig(FIG / "capability-signals.png", dpi=190)
plt.close(fig)

results = {
    "report_number": "SHWRP-2026-008",
    "coding_date": "2026-07-13",
    "case_count": int(len(df)),
    "traditional_cases": int((df["group"] == "traditional").sum()),
    "integrated_cases": int((df["group"] == "integrated").sum()),
    "source_urls": int(len(audit)),
    "successful_text_pages": int(audit["text_available"].sum()),
    "source_grade_counts": {str(k): int(v) for k, v in df["source_grade"].value_counts().sort_index().items()},
    "index_comparisons": comparisons,
    "spearman": {
        "platform_leverage_owned_assets": {"rho": float(rho_platform_owned_assets.statistic), "p_value": float(rho_platform_owned_assets.pvalue)},
        "platform_differentiation": {"rho": float(rho_platform_diff.statistic), "p_value": float(rho_platform_diff.pvalue)},
    },
    "strategy_counts": {
        group: {strategy: int(strategy_table.loc[group, strategy]) for strategy in strategy_order}
        for group in strategy_table.index
    },
    "signal_shares_pct": {
        group: {signal: float(signal_shares.loc[group, signal]) for signal in signals}
        for group in signal_shares.index
    },
    "high_confidence_ab_cases": int(len(high_conf)),
    "sensitivity_ab": sensitivity,
    "qualitative_case_ids": qualitative["id"].tolist(),
    "design_note": "Fixed stratified purposive sample; comparisons describe public disclosure patterns and do not identify performance or causal effects.",
    "concentration_proxy_note": "Public-channel concentration proxy only; not revenue dependence, contractual dependence, switching cost, platform bargaining power, or legal compliance.",
    "single_coder_note": "Exploratory single-researcher coding; no intercoder reliability statistic is claimed.",
}
(ROOT / "analysis-results.json").write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8")
print(json.dumps(results, ensure_ascii=False, indent=2))
