from __future__ import annotations

import hashlib
import json
from datetime import datetime
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
TARGET = ROOT / "app"
OUTPUT = ROOT / "docs" / "migration" / "原版资产清单.json"

DIRECTORIES = (
    "backend",
    "config",
    "static",
    "tests",
    "tools",
    "vendor",
    "游资skills",
)

ROOT_FILES = (
    ".dockerignore",
    ".env.example",
    ".gitignore",
    "advanced_strategies.py",
    "alert_service.py",
    "api_access.py",
    "app_config.py",
    "ARCHITECTURE.md",
    "assistant_agent.py",
    "chart_data_provider.py",
    "compose.yaml",
    "database.py",
    "demo_data.py",
    "Dockerfile",
    "DOCKER_DEPLOY.md",
    "heaven_agent.py",
    "heaven_engine.py",
    "ifind_client.py",
    "llm_strategy.py",
    "llm_stream.py",
    "market_insights.py",
    "mentor_agent.py",
    "package-lock.json",
    "package.json",
    "playwright.config.js",
    "README.md",
    "realtime_aggregator.py",
    "requirements.txt",
    "screener.py",
    "security.py",
    "sentiment_engine.py",
    "server.py",
    "strategy_tracking.py",
    "sync_data.py",
    "THIRD_PARTY_NOTICES.md",
    "trade_journal.py",
    "tushare_client.py",
)


def digest(path: Path) -> str:
    checksum = hashlib.sha256()
    with path.open("rb") as handle:
        for block in iter(lambda: handle.read(1024 * 1024), b""):
            checksum.update(block)
    return checksum.hexdigest()


def source_files() -> list[Path]:
    files = [ROOT / name for name in ROOT_FILES]
    for directory in DIRECTORIES:
        files.extend(
            path
            for path in (ROOT / directory).rglob("*")
            if path.is_file() and "__pycache__" not in path.parts
        )
    return sorted(set(files), key=lambda path: path.relative_to(ROOT).as_posix())


def build_manifest() -> dict[str, object]:
    assets = []
    mismatches = []
    for source in source_files():
        relative = source.relative_to(ROOT)
        target = TARGET / relative
        source_hash = digest(source)
        target_hash = digest(target) if target.is_file() else ""
        status = "identical" if source_hash == target_hash else "mismatch"
        if status != "identical":
            mismatches.append(relative.as_posix())
        assets.append(
            {
                "source": relative.as_posix(),
                "target": f"app/{relative.as_posix()}",
                "bytes": source.stat().st_size,
                "sha256": source_hash,
                "disposition": "original_copy_pending_move",
                "status": status,
            }
        )
    return {
        "schema_version": 1,
        "generated_at": datetime.now().astimezone().isoformat(timespec="seconds"),
        "source_commit": "41329943c4878fc09ed82ec376eb93ab151e4092",
        "source_root": ".",
        "target_root": "app",
        "excluded": [
            "next/",
            "data/review.db and SQLite sidecars",
            "data/private-mentor-skills/",
            ".env",
            "node_modules/",
            "logs, caches and generated test results",
        ],
        "asset_count": len(assets),
        "mismatch_count": len(mismatches),
        "mismatches": mismatches,
        "assets": assets,
    }


def main() -> int:
    manifest = build_manifest()
    OUTPUT.write_text(
        json.dumps(manifest, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    print(
        f"assets={manifest['asset_count']} mismatches={manifest['mismatch_count']} "
        f"output={OUTPUT}"
    )
    return 1 if manifest["mismatch_count"] else 0


if __name__ == "__main__":
    raise SystemExit(main())
