#!/usr/bin/env python3
"""Generate filtered DBSCAN results based on images listed in 009_label_data_sample_seed_42.json.

Rules (v1): keep only entries whose base filename (before _<idx>_scale_* suffix or extension)
can be matched with any "image" field in the label JSON. Matching strategy:
  - Extract filename without extension from each DBSCAN result filepath.
  - Remove trailing pattern: _<digits>_scale_<anything>
  - For each image name from labels, keep the DBSCAN entry if:
       * cleaned_filename startswith(image_name) OR
       * image_name startswith(cleaned_filename) OR
       * image_name in cleaned_filename OR cleaned_filename in image_name
  - This permissive logic aims to cover variations; can be tightened later.

Outputs file: dbscan_results_filter.json in the same folder with structure:
{
  "method": "DBSCAN_FILTERED",
  "n_samples": <count_of_original>,
  "n_filtered": <count_after_filter>,
  "results": [ ...filtered entries... ]
}
"""
from __future__ import annotations
import json
import re
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent
# LABEL_FILE = BASE_DIR / "009_label_data_sample_seed_42.json"
LABEL_FILE = BASE_DIR / "015_label_data_sample_seed_1997.json"
LABEL_FILE = BASE_DIR / "008_label_data_sample_seed_1997.json"



# Prefer the clustering output in cluster/ directory relative to project root
# DBSCAN_FILE_CANDIDATES = [
#     BASE_DIR.parent / "cluster" / "dbscan_results.json",
#     BASE_DIR.parent / "result" / "dbscan_results.json",
# ]

DBSCAN_FILE_CANDIDATES = [
    BASE_DIR.parent / "cluster" / "dbscan_results.json",
    BASE_DIR.parent / "result" / "dbscan_results.json",
]
OUTPUT_FILE = BASE_DIR / "dbscan_results_filter_008.json"

def load_first_existing(paths):
    for p in paths:
        if p.exists():
            return p
    raise FileNotFoundError("No dbscan_results.json file found in expected locations: " + ", ".join(map(str, paths)))

def normalize_image_name(name: str) -> str:
    return name.strip()

def cleaned_filename(path: str) -> str:
    stem = Path(path).stem  # remove extension
    stem = re.sub(r"_[0-9]+_scale_.*$", "", stem)
    return stem

def build_image_name_set(label_path: Path) -> set[str]:
    data = json.loads(label_path.read_text())
    names: set[str] = set()
    for entry in data:
        if not isinstance(entry, dict):
            continue
        img = entry.get("image")
        if isinstance(img, str) and img.strip():
            names.add(normalize_image_name(img))
    return names

def match_entry(core_name: str, image_names: set[str]) -> bool:
    for img in image_names:
        if core_name.startswith(img) or img.startswith(core_name):
            return True
        if img in core_name or core_name in img:
            return True
    return False

def main():
    dbscan_file = load_first_existing(DBSCAN_FILE_CANDIDATES)
    image_names = build_image_name_set(LABEL_FILE)
    raw = json.loads(dbscan_file.read_text())
    results = raw.get("results", [])
    filtered = []
    for rec in results:
        filepath = rec.get("filepath")
        if not filepath:
            continue
        core = cleaned_filename(filepath)
        if match_entry(core, image_names):
            filtered.append(rec)
    out = {
        "method": "DBSCAN_FILTERED",
        "n_samples": len(results),
        "n_filtered": len(filtered),
        "match_ratio": round(len(filtered) / len(results), 4) if results else 0.0,
        "source_file": str(dbscan_file),
        "label_source": str(LABEL_FILE),
        "results": filtered,
    }
    OUTPUT_FILE.write_text(json.dumps(out, indent=2, ensure_ascii=False))
    print(f"Wrote {len(filtered)} filtered results to {OUTPUT_FILE}")

if __name__ == "__main__":  # pragma: no cover
    main()
