#!/usr/bin/env python3
"""读取从生产导出的 CSV 指南文献，解析标题，输出 INSERT SQL 脚本。

用法:
  # 1. 在生产导出数据
  ssh root@... "docker exec scilit-postgres-1 psql -U scilit -d scilit -A -F',' -c \"
    SELECT id, pmid, title, pub_date::text FROM global_literature
    WHERE pub_types IS NOT NULL
      AND lower(pub_types::text) LIKE '%guideline%'
      AND (title ILIKE '%NCCN%' OR title ILIKE '%CSCO%' OR title ILIKE '%ESMO%'
           OR title ILIKE '%ASCO%' OR title ILIKE '%ASTRO%')
  \" > /tmp/guidelines.csv"

  # 2. 导出到本地
  scp root@123.207.9.209:/tmp/guidelines.csv /tmp/

  # 3. 生成 SQL
  cd backend && python scripts/gen_guideline_sql.py --input /tmp/guidelines.csv --output /tmp/insert_guidelines.sql

  # 4. 发回生产执行
  scp /tmp/insert_guidelines.sql root@123.207.9.209:/tmp/
  ssh root@123.207.9.209 "docker exec -i scilit-postgres-1 psql -U scilit -d scilit < /tmp/insert_guidelines.sql"
"""

import argparse
import csv
import re
import uuid
from collections import defaultdict

# ============== 标题解析（与 seed_guidelines.py 一致）==============

def clean_title(title: str) -> str:
    t = title.encode('utf-8', errors='ignore').decode('utf-8', errors='ignore')
    for ch in ['®', '©', '™', '°']:
        t = t.replace(ch, '')
    return re.sub(r'\s+', ' ', t).strip()

SOURCES = ('NCCN', 'ESMO', 'ASCO', 'ASTRO', 'CSCO')

NCCN_PATTERNS = [
    re.compile(r'NCCN\s+Guidelines?\s+Insights?:\s+(?P<cancer>[^,]+)(?:,\s+Version\s+(?P<ver>[\d.v]+))?(?:\s|\.|$)', re.I),
    re.compile(r'NCCN\s+Clinical\s+Practice\s+Guidelines?\s+in\s+Oncology:\s+(?P<cancer>[^,]+)(?:,\s+Version\s+(?P<ver>[\d.v]+))?(?:\s|\.|$)', re.I),
    re.compile(r'(?P<cancer>[^,]+),\s+Version\s+(?P<ver>[\d.v]+),\s+NCCN\s+Clinical\s+Practice\s+Guidelines?\s+in\s+Oncology', re.I),
    re.compile(r'NCCN\s+Guidelines?\s+(?:for\s+)?(?:the\s+)?(?:management\s+of\s+)?(?P<cancer>[^,\.]+)', re.I),
    re.compile(r'NCCN\s+Guidelines?\s+Update\s+for\s+(?P<cancer>[^,\.]+)', re.I),
    re.compile(r'NCCN\s+Guidelines?\s+for\s+(?P<cancer>[^,\.]+)', re.I),
]
ESMO_PATTERNS = [
    re.compile(r'ESMO\s+Clinical\s+Practice\s+Guidelines?\s+for\s+(?:the\s+)?(?:management\s+of\s+)?(?:patients\s+with\s+)?(?P<cancer>[^\.]+)', re.I),
    re.compile(r'ESMO\s+Guidelines?:\s+(?P<cancer>[^\.]+)', re.I),
    re.compile(r'(?:Pan-Asian\s+)?adapted\s+ESMO\s+Clinical\s+Practice\s+Guidelines?\s+for\s+(?:the\s+)?(?:management\s+of\s+)?(?:patients\s+with\s+)?(?P<cancer>[^\.:]+)', re.I),
]
ASCO_PATTERNS = [
    re.compile(r'ASCO\s+(?:Clinical\s+Practice\s+)?Guidelines?\s+(?:for\s+)?(?:the\s+)?(?:management\s+of\s+)?(?:patients\s+with\s+)?(?P<cancer>[^\.]+)', re.I),
    re.compile(r'ASCO\s+endorsement\s+of\s+(?P<cancer>[^\.]+)', re.I),
    re.compile(r'ASCO\s+.*?Guidelines?\s+for\s+(?P<cancer>[^\.]+)', re.I),
]
ASTRO_PATTERNS = [
    re.compile(r'(?:Executive\s+Summary\s+of\s+)?[Aa]n?\s+ASTRO\s+Clinical\s+Practice\s+Guidelines?'),
    re.compile(r'ASTRO\s+(?:Radiation\s+Therapy\s+)?Summary\s+of\s+the\s+'),
    re.compile(r'ASTRO\s+.*?Guidelines?\s+for\s+(?P<cancer>[^\.]+)', re.I),
]
ASTRO_CANCER_RE = re.compile(r'(?:for|of)\s+(?:the\s+)?(?:treatment\s+of\s+)?(?:primary\s+)?(?P<cancer>[^:]+?)(?::|$)', re.I)
FALLBACK_NCCN_RE = re.compile(r'^(?P<cancer>[^,]+?)(?:,\s+Version|\s*\||$)', re.I)

CANCER_KEYWORD_MAP: dict[str, str] = {
    'non-small cell lung': 'Non-Small Cell Lung Cancer',
    'nsclc': 'Non-Small Cell Lung Cancer',
    'small cell lung': 'Small Cell Lung Cancer',
    'sclc': 'Small Cell Lung Cancer',
    'lung cancer screening': 'Lung Cancer Screening',
    'lung cancer': 'Lung Cancer',
    'mesothelioma': 'Mesothelioma',
    'breast cancer': 'Breast Cancer',
    'breast': 'Breast Cancer',
    'gastric cancer': 'Gastric Cancer',
    'gastric': 'Gastric Cancer',
    'stomach': 'Gastric Cancer',
    'colorectal cancer': 'Colorectal Cancer',
    'colorectal': 'Colorectal Cancer',
    'colon cancer': 'Colorectal Cancer',
    'rectal cancer': 'Rectal Cancer',
    'hepatocellular carcinoma': 'Hepatocellular Carcinoma',
    'hepatocellular': 'Hepatocellular Carcinoma',
    'hcc': 'Hepatocellular Carcinoma',
    'liver cancer': 'Hepatocellular Carcinoma',
    'liver': 'Hepatocellular Carcinoma',
    'pancreatic cancer': 'Pancreatic Cancer',
    'pancreatic': 'Pancreatic Cancer',
    'prostate cancer': 'Prostate Cancer',
    'prostate': 'Prostate Cancer',
    'melanoma': 'Melanoma',
    'ovarian cancer': 'Ovarian Cancer',
    'ovarian': 'Ovarian Cancer',
    'head and neck': 'Head and Neck Cancer',
    'esophageal': 'Esophageal Cancer',
    'esophagus': 'Esophageal Cancer',
    'oesophageal': 'Esophageal Cancer',
    'renal cell carcinoma': 'Renal Cell Carcinoma',
    'renal cell': 'Renal Cell Carcinoma',
    'rcc': 'Renal Cell Carcinoma',
    'kidney cancer': 'Renal Cell Carcinoma',
    'bladder cancer': 'Bladder Cancer',
    'urothelial': 'Bladder Cancer',
    'cervical cancer': 'Cervical Cancer',
    'cervical': 'Cervical Cancer',
    'leukemia': 'Leukemia',
    'lymphoma': 'Lymphoma',
    'hodgkin': 'Hodgkin Lymphoma',
    'multiple myeloma': 'Multiple Myeloma',
    'myeloma': 'Multiple Myeloma',
    'glioma': 'Glioma',
    'glioblastoma': 'Glioblastoma',
    'gbm': 'Glioblastoma',
    'thyroid cancer': 'Thyroid Cancer',
    'endometrial': 'Endometrial Cancer',
    'uterine': 'Endometrial Cancer',
    'soft tissue sarcoma': 'Sarcoma',
    'sarcoma': 'Sarcoma',
    'gist': 'Gastrointestinal Stromal Tumor',
    'neuroendocrine': 'Neuroendocrine Tumor',
    'anal cancer': 'Anal Cancer',
    'nasopharyngeal': 'Nasopharyngeal Carcinoma',
    'brain metastases': 'Brain Metastases',
    'brain tumor': 'Brain Tumor',
    'penile cancer': 'Penile Cancer',
    'vulvar': 'Vulvar Cancer',
    'vaginal': 'Vaginal Cancer',
}

def normalize_cancer_name(raw: str) -> str | None:
    lower = raw.lower().strip()
    for kw, name in sorted(CANCER_KEYWORD_MAP.items(), key=lambda x: -len(x[0])):
        if kw in lower:
            return name
    return None

def extract_meta(title: str) -> dict | None:
    c = clean_title(title)
    upper = c.upper()
    source = None
    for s in SOURCES:
        if s in upper:
            source = s
            break
    if not source:
        return None

    patterns = {'NCCN': NCCN_PATTERNS, 'ESMO': ESMO_PATTERNS, 'ASCO': ASCO_PATTERNS,
                'ASTRO': ASTRO_PATTERNS, 'CSCO': []}.get(source, [])
    cancer_raw = None
    version = None
    for pat in patterns:
        m = pat.search(c)
        if m:
            cancer_raw = (m.groupdict().get('cancer') or '').strip().rstrip('.,; ')
            ver = m.groupdict().get('ver', '')
            if ver:
                version = ver.strip()
            break
    if source == 'ASTRO' and not cancer_raw:
        m2 = ASTRO_CANCER_RE.search(c)
        if m2:
            cancer_raw = m2.group('cancer').strip().rstrip('.,; ')
    if source == 'NCCN' and not cancer_raw:
        m = FALLBACK_NCCN_RE.search(c)
        if m:
            cancer_raw = m.group('cancer').strip()
    if not cancer_raw:
        return None
    if not version:
        vm = re.search(r'Version\s+([\d.v]+)', c, re.IGNORECASE)
        if vm:
            version = vm.group(1)
    return {'source': source, 'cancer_raw': cancer_raw, 'version': version or ''}


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', required=True)
    parser.add_argument('--output', required=True)
    args = parser.parse_args()

    # 读取 CSV
    rows = []
    with open(args.input, encoding='utf-8') as f:
        reader = csv.reader(f, delimiter='\t')
        header = next(reader)
        for row in reader:
            if len(row) >= 4:
                rows.append((row[0], row[1], row[2], row[3]))

    print(f"读取 {len(rows)} 条记录")

    # 解析
    parsed = []
    for lit_id, pmid, title, pub_date in rows:
        meta = extract_meta(title)
        if not meta:
            continue
        cancer = normalize_cancer_name(meta['cancer_raw'])
        if not cancer:
            continue
        version = meta['version'] or (pub_date[:4] if pub_date else '')
        if not version:
            continue
        parsed.append({
            'lit_id': lit_id,
            'pmid': pmid,
            'title': title,
            'pub_date': pub_date,
            'source': meta['source'],
            'cancer_raw': meta['cancer_raw'],
            'cancer': cancer,
            'version': version,
        })

    print(f"成功解析: {len(parsed)} 条")
    skip = len(rows) - len(parsed)
    if skip:
        print(f"跳过（无法解析）: {skip} 条")

    # 标签映射（使用生产库中存在 tag name_en，ILIKE 回退用）
    CANCER_TAG_MAP = {
        # NSCLC/SCLC/Lung → Lung Cancer（无单独 NSCLC 标签）
        'Non-Small Cell Lung Cancer': ('Lung Cancer', '%lung cancer%'),
        'Small Cell Lung Cancer': ('Lung Cancer', '%lung cancer%'),
        'Lung Cancer Screening': ('Lung Cancer', '%lung cancer%'),
        'Lung Cancer': ('Lung Cancer', '%lung cancer%'),
        'Breast Cancer': ('Breast Cancer', '%breast cancer%'),
        'Gastric Cancer': ('Gastric Cancer', '%gastric cancer%'),
        'Colorectal Cancer': ('Colorectal Cancer', '%colorectal cancer%'),
        'Rectal Cancer': ('Rectal Neoplasms', '%rectal neoplasm%'),
        'Pancreatic Cancer': ('Pancreatic Cancer', '%pancreatic cancer%'),
        'Prostate Cancer': ('Prostate Cancer', '%prostate cancer%'),
        'Hepatocellular Carcinoma': ('Liver Cancer', '%liver cancer%'),
        'Liver Cancer': ('Liver Cancer', '%liver cancer%'),
        'Melanoma': ('Melanoma', '%melanoma%'),
        'Leukemia': ('Leukemia', '%leukemia%'),
        'Lymphoma': ('Lymphoma', '%lymphoma%'),
        'Hodgkin Lymphoma': ('Hodgkin Disease', '%hodgkin%'),
        'Multiple Myeloma': ('Multiple Myeloma', '%multiple myeloma%'),
        'Glioma': ('Glioma', '%glioma%'),
        'Glioblastoma': ('Glioma', '%glioma%'),  # 没有单独 Glioblastoma 标签
        'Ovarian Cancer': ('Ovarian Cancer', '%ovarian cancer%'),
        'Head and Neck Cancer': ('Head and Neck Cancer', '%head and neck cancer%'),
        'Esophageal Cancer': ('Esophageal Cancer', '%esophageal cancer%'),
        'Cervical Cancer': ('Cervical Cancer', '%cervical cancer%'),
        'Bladder Cancer': ('Urinary Bladder Neoplasms', '%bladder neoplasm%'),
        'Renal Cell Carcinoma': ('Renal Cell Carcinoma', '%renal cell carcinoma%'),
        'Thyroid Cancer': ('Thyroid Neoplasms', '%thyroid neoplasm%'),
        'Endometrial Cancer': ('Endometrial Neoplasms', '%endometrial neoplasm%'),
        'Sarcoma': ('Sarcoma', '%sarcoma%'),
        'Gastrointestinal Stromal Tumor': ('Gastrointestinal Stromal Tumor', '%gist%'),
        'Neuroendocrine Tumor': ('Neuroendocrine Tumors', '%neuroendocrine tumor%'),
        'Anal Cancer': ('Anal Gland Neoplasms', '%anal gland neoplasm%'),
        'Nasopharyngeal Carcinoma': ('Nasopharyngeal Carcinoma', '%nasopharyngeal carcinoma%'),
        'Mesothelioma': ('Mesothelioma', '%mesothelioma%'),
        'Vulvar Cancer': ('Vulvar Neoplasms', '%vulvar neoplasm%'),
        'Vaginal Cancer': ('Vulvar Neoplasms', '%vulvar neoplasm%'),
        'Penile Cancer': ('Urinary Bladder Neoplasms', '%penile%'),  # fallback
        'Brain Metastases': ('Lung Cancer', '%metasta%'),  # 无直接对应标签
        'Brain Tumor': ('Glioma', '%brain%'),
    }

    # 生成 SQL
    sql_parts = [
        "-- 自动生成的指南导入 SQL",
        f"-- {len(parsed)} 条解析成功",
        "",
        "BEGIN;",
        "",
        "-- 查找 tag UUID 的函数",
        """
CREATE OR REPLACE FUNCTION _tmp_tag_id(cat TEXT, en_name TEXT, ilike_pattern TEXT)
RETURNS UUID LANGUAGE SQL STABLE AS $$
  SELECT id FROM global_tags
  WHERE tag_category = cat AND is_active = true
    AND (name_en = en_name OR name_en ILIKE ilike_pattern)
  LIMIT 1
$$;
""",
    ]

    gv_inserts = []
    ev_inserts = []
    by_source: dict[str, list] = defaultdict(set)
    dedup_keys: set[tuple] = set()

    for rec in parsed:
        cancer = rec['cancer']
        source = rec['source']
        version = rec['version']

        mapped = CANCER_TAG_MAP.get(cancer)
        if not mapped:
            continue

        tag_cat, tag_ilike = mapped
        key = (source, cancer, version)
        if key in dedup_keys:
            continue
        dedup_keys.add(key)

        gv_id = uuid.uuid4()
        ev_id = uuid.uuid4()
        by_source[source].add(cancer)

        title_escaped = rec['title'].replace("'", "''")
        change_summary = f"Based on: {title_escaped[:200]}"
        pub_date = rec['pub_date'] or 'NULL'
        if pub_date != 'NULL':
            pub_date = f"'{pub_date}'"

        gv_inserts.append(f"""WITH tag AS (SELECT _tmp_tag_id('cancer', '{tag_cat}', '{tag_ilike}') AS tid)
INSERT INTO guideline_versions (id, guideline_source, cancer_type_tag_id, version, publish_date, change_summary_en)
SELECT '{gv_id}'::uuid, '{source}', tid, '{version}', {pub_date}::date, '{change_summary}'
FROM tag WHERE tid IS NOT NULL;""")

        ev_inserts.append(f"""INSERT INTO guideline_evidence (id, guideline_version_id, literature_id, recommendation)
SELECT '{ev_id}'::uuid, '{gv_id}'::uuid, '{rec['lit_id']}'::uuid, '{title_escaped[:200]}'
WHERE EXISTS (SELECT 1 FROM guideline_versions WHERE id = '{gv_id}'::uuid);""")

    sql_parts.extend(gv_inserts)
    sql_parts.append("")
    sql_parts.extend(ev_inserts)
    sql_parts.append("")
    sql_parts.append("DROP FUNCTION IF EXISTS _tmp_tag_id;")
    sql_parts.append("")
    sql_parts.append("COMMIT;")

    sql = "\n".join(sql_parts)

    with open(args.output, 'w', encoding='utf-8') as f:
        f.write(sql)

    print(f"\nSQL 已写入: {args.output}")
    print(f"指南版本: {len(gv_inserts)} 条")
    print(f"证据关联: {len(ev_inserts)} 条")
    print(f"\n按来源:")
    for src, cancers in sorted(by_source.items()):
        print(f"  {src}: {len(cancers)} 种癌种 — {', '.join(sorted(cancers))}")


if __name__ == '__main__':
    main()
