import csv
from pathlib import Path

ROOT = Path(r"C:\Users\user\Documents\New project\KOUCHA_GOLD_LATE_SINGLE_FATAL_EXIT_COMPARE")
DEPOSIT = 50000.0
ORDER_EVENTS = {"ENTRY_BUY", "ENTRY_SELL", "ADD_BUY", "ADD_SELL", "DEFENSE_HEDGE_BUY", "DEFENSE_HEDGE_SELL"}
CLOSE_EVENTS = {
    "BASKET_CLOSE", "BASKET_RECOVERY_CLOSE", "BASKET_RECOVERY_LOSSCUT_CLOSE",
    "HEDGED_BASKET_TIME_EXIT", "HARDSTOP_CLOSE", "SINGLE_CONTRARY_EARLY_EXIT",
    "STRUCTURE_BASED_EARLY_EXIT", "HEDGED_BASKET_LOSS_COMPRESSION"
}

def read_csv(path):
    if not path.exists():
        return []
    with path.open("r", encoding="utf-8-sig", newline="") as f:
        return list(csv.DictReader(f))

def write_csv(path, rows):
    fields = []
    for row in rows:
        for key in row:
            if key not in fields:
                fields.append(key)
    with path.open("w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore")
        writer.writeheader()
        writer.writerows(rows)

def fnum(v, default=0.0):
    try:
        if v is None or v == "":
            return default
        return float(str(v).replace(",", ""))
    except Exception:
        return default

def inum(v, default=0):
    try:
        if v is None or v == "":
            return default
        return int(float(str(v).replace(",", "")))
    except Exception:
        return default

def newest(test_dir, suffix):
    files = sorted(test_dir.glob(f"*{suffix}"), key=lambda p: p.stat().st_mtime, reverse=True)
    return files[0] if files else None

def max_drawdown(rows):
    peak = DEPOSIT
    dd = 0.0
    for row in rows:
        bal = fnum(row.get("Balance"), peak)
        eq = fnum(row.get("Equity"), bal)
        peak = max(peak, bal, eq)
        dd = max(dd, peak - eq)
    return round(dd, 2)

def count(rows, event_type):
    return sum(1 for row in rows if row.get("EventType") == event_type)

def profit(rows, event_type):
    return round(sum(fnum(row.get("ProfitYen")) for row in rows if row.get("EventType") == event_type), 2)

def profit_factor(rows):
    gross_profit = 0.0
    gross_loss = 0.0
    for row in rows:
        if row.get("EventType") in CLOSE_EVENTS:
            p = fnum(row.get("ProfitYen"))
            if p > 0:
                gross_profit += p
            elif p < 0:
                gross_loss += abs(p)
    if gross_loss <= 0:
        return round(gross_profit, 2) if gross_profit > 0 else 0.0
    return round(gross_profit / gross_loss, 4)

def last_nonblank(rows, field, default=""):
    for row in reversed(rows):
        value = row.get(field, "")
        if value != "":
            return value
    return default

def audit_last_value(audit, field):
    for row in reversed(audit):
        if row.get("AuditType") in ("FINAL_SUMMARY", "PERIODIC_SUMMARY", "DAILY_SUMMARY"):
            return inum(row.get(field))
    return 0

def summarize_test(row):
    test_dir = Path(row["Ini"]).parent
    events_path = newest(test_dir, "_trade_events.csv")
    audit_path = newest(test_dir, "_entry_opportunity_audit.csv")
    events = read_csv(events_path) if events_path else []
    audit = read_csv(audit_path) if audit_path else []

    balances = [fnum(r.get("Balance")) for r in events if r.get("Balance", "") != ""]
    equities = [fnum(r.get("Equity")) for r in events if r.get("Equity", "") != ""]
    final_balance = balances[-1] if balances else DEPOSIT
    final_equity = equities[-1] if equities else final_balance
    early_rows = [r for r in events if r.get("EventType") == "SINGLE_CONTRARY_EARLY_EXIT"]
    early_profit = profit(events, "SINGLE_CONTRARY_EARLY_EXIT")
    early_count = len(early_rows)

    return {
        "Pattern": row["Pattern"],
        "TestName": row["TestName"],
        "SegmentStart": row["FromDate"],
        "SegmentEnd": row["ToDate"],
        "FinalBalance": round(final_balance, 2),
        "FinalEquity": round(final_equity, 2),
        "NetProfit": round(final_balance - DEPOSIT, 2),
        "ProfitFactor": profit_factor(events),
        "MaxDrawdown": max_drawdown(events),
        "TotalTrades": sum(1 for r in events if r.get("EventType") in ORDER_EVENTS),
        "BasketCloseCount": count(events, "BASKET_CLOSE"),
        "BasketCloseProfitTotal": profit(events, "BASKET_CLOSE"),
        "HedgedBasketTimeExitCount": count(events, "HEDGED_BASKET_TIME_EXIT"),
        "HedgedBasketTimeExitProfitTotal": profit(events, "HEDGED_BASKET_TIME_EXIT"),
        "BasketRecoveryCloseCount": count(events, "BASKET_RECOVERY_CLOSE"),
        "BasketRecoveryLossCutCount": count(events, "BASKET_RECOVERY_LOSSCUT_CLOSE"),
        "SinglePositionContraryEarlyExitCount": early_count,
        "SinglePositionContraryEarlyExitProfitTotal": early_profit,
        "SinglePositionContraryEarlyExitAverageLoss": round(early_profit / early_count, 2) if early_count else 0.0,
        "SingleEarlyExitPostCooldownBlockCount": max([inum(r.get("SingleEarlyExitPostCooldownBlockCount")) for r in events] or [0]),
        "SameDirectionReentryBlockedAfterSingleEarlyExitCount": max([inum(r.get("SameDirectionReentryBlockedAfterSingleEarlyExitCount")) for r in events] or [0]),
        "MaxSingleEarlyExitPerDayHitCount": max([inum(r.get("MaxSingleEarlyExitPerDayHitCount")) for r in events] or [0]),
        "M5ConfirmationPassedCount": max([inum(r.get("M5ConfirmationPassedCount")) for r in events] or [0]),
        "M5ConfirmationFailedCount": max([inum(r.get("M5ConfirmationFailedCount")) for r in events] or [0]),
        "DefenseHedgeCount": count(events, "DEFENSE_HEDGE_BUY") + count(events, "DEFENSE_HEDGE_SELL"),
        "HardStopCount": count(events, "HARDSTOP_CLOSE"),
        "DailyLossStopCount": count(events, "DAILY_LOSS_STOP"),
        "ConsecutiveLossStopCount": count(events, "CONSECUTIVE_LOSS_STOP"),
        "NoMoneyOrderFailedCount": sum(1 for r in events if r.get("Retcode") == "10019" or "not enough money" in r.get("RetcodeDescription", "")),
        "BlockedByHistoricalTimeRiskCount": audit_last_value(audit, "BlockedByHistoricalTimeRiskCount"),
        "BlockedByNewsCount": audit_last_value(audit, "BlockedByNewsCount"),
        "TradeEventsFileSizeKB": round((events_path.stat().st_size if events_path and events_path.exists() else 0) / 1024, 2),
        "AuditSummaryFileSizeKB": round((audit_path.stat().st_size if audit_path and audit_path.exists() else 0) / 1024, 2),
        "Comment": "compiled from TradeEventLog and EntryOpportunityAudit SUMMARY",
    }

def main():
    manifest = read_csv(ROOT / "late_single_fatal_exit_manifest.csv")
    rows = []
    for item in manifest:
        test_dir = Path(item["Ini"]).parent
        if newest(test_dir, "_trade_events.csv"):
            rows.append(summarize_test(item))
    write_csv(ROOT / "late_single_fatal_exit_s2_summary.csv", rows)

    early = []
    cooldown = []
    m5 = []
    hard = []
    for item in manifest:
        test_dir = Path(item["Ini"]).parent
        events_path = newest(test_dir, "_trade_events.csv")
        if not events_path:
            continue
        for event in read_csv(events_path):
            event["Pattern"] = item["Pattern"]
            event["TestName"] = item["TestName"]
            if event.get("EventType") == "SINGLE_CONTRARY_EARLY_EXIT":
                early.append(event)
            if event.get("EventType") == "SINGLE_EARLY_EXIT_POST_COOLDOWN_BLOCK":
                cooldown.append(event)
            if event.get("EventType") == "SINGLE_CONTRARY_EARLY_EXIT" or event.get("M5ConfirmationPassed", "") != "":
                m5.append(event)
            if event.get("EventType") == "HARDSTOP_CLOSE":
                hard.append(event)

    write_csv(ROOT / "single_contrary_early_exit_events.csv", early)
    write_csv(ROOT / "single_early_exit_post_cooldown_block_events.csv", cooldown)
    write_csv(ROOT / "m5_confirmation_results.csv", m5)
    write_csv(ROOT / "hardstop_remaining_events.csv", hard)

    base = next((r for r in rows if r["Pattern"] == "A2_BASE"), None)
    improved = []
    if base:
        base_profit = fnum(base["NetProfit"])
        for row in rows:
            if row["Pattern"] != "A2_BASE" and fnum(row["NetProfit"]) > base_profit:
                improved.append(row["Pattern"])

    aggregate_rows = []
    for row in rows:
        aggregate_rows.append({
            "Pattern": row["Pattern"],
            "TotalNetProfit": row["NetProfit"],
            "WorstSegmentNetProfit": row["NetProfit"],
            "BestSegmentNetProfit": row["NetProfit"],
            "TotalTrades": row["TotalTrades"],
            "TotalBasketCloseProfit": row["BasketCloseProfitTotal"],
            "TotalHedgedBasketTimeExitProfit": row["HedgedBasketTimeExitProfitTotal"],
            "TotalSingleEarlyExitProfit": row["SinglePositionContraryEarlyExitProfitTotal"],
            "TotalSingleEarlyExitCount": row["SinglePositionContraryEarlyExitCount"],
            "TotalHardStopCount": row["HardStopCount"],
            "MaxSegmentDrawdown": row["MaxDrawdown"],
            "NoMoneyOrderFailedCount": row["NoMoneyOrderFailedCount"],
            "CompletedSegments": 1,
            "Comment": "S2 only; other segments should run only for S2-improved candidates",
        })
    write_csv(ROOT / "late_single_fatal_exit_four_segment_aggregate_summary.csv", aggregate_rows)

    lines = [
        "# Late Single Fatal Exit Compare Summary",
        "",
        "## S2 Results",
    ]
    for row in rows:
        lines.append(
            f"- {row['Pattern']}: NetProfit={row['NetProfit']}, HardStop={row['HardStopCount']}, "
            f"SingleExit={row['SinglePositionContraryEarlyExitCount']}, "
            f"SingleExitProfit={row['SinglePositionContraryEarlyExitProfitTotal']}, "
            f"DD={row['MaxDrawdown']}, Trades={row['TotalTrades']}"
        )
    lines.append("")
    if improved:
        lines.append("## Decision")
        lines.append("S2 improved candidates: " + ", ".join(improved))
        lines.append("Run the remaining three segments only for these candidates.")
    else:
        lines.append("## Decision")
        lines.append("No F pattern improved over A2_BASE in S2. Per rule, do not expand to the other three segments.")
    (ROOT / "late_single_fatal_exit_summary.md").write_text("\n".join(lines), encoding="utf-8")

if __name__ == "__main__":
    main()
