#!/usr/bin/env python3
# fix_canonical.py — topeduprep.uk canonical 태그 자동 삽입
# 사용법: python3 fix_canonical.py

import os
import re
import shutil
from datetime import datetime

BASE_URL = "https://topeduprep.uk"
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
BACKUP_DIR = os.path.join(SCRIPT_DIR, "_canonical_backup_" + datetime.now().strftime("%Y%m%d_%H%M%S"))
LOG_FILE = os.path.join(SCRIPT_DIR, "canonical_log.txt")

def get_url_path(filepath):
    """파일 경로 → URL 경로 변환"""
    rel = os.path.relpath(filepath, SCRIPT_DIR)
    # Windows 경로 구분자 대응
    rel = rel.replace("\\", "/")
    # 스크립트 자신, 백업 폴더, 숨김 파일 제외
    if rel.startswith("_canonical_backup") or rel.startswith("."):
        return None
    return "/" + rel

def has_canonical(content):
    """이미 canonical 태그가 있는지 확인"""
    return bool(re.search(r'<link[^>]+rel=["\']canonical["\']', content, re.IGNORECASE))

def replace_canonical(content, url):
    """기존 canonical 태그를 새 URL로 교체"""
    new_tag = f'<link rel="canonical" href="{url}">'
    return re.sub(
        r'<link[^>]+rel=["\']canonical["\'][^>]*>',
        new_tag,
        content,
        flags=re.IGNORECASE
    )

def insert_canonical(content, url):
    """<head> 바로 다음에 canonical 태그 삽입"""
    new_tag = f'\n  <link rel="canonical" href="{url}">'
    return re.sub(
        r'(<head[^>]*>)',
        r'\1' + new_tag,
        content,
        count=1,
        flags=re.IGNORECASE
    )

def process_file(filepath, dry_run=True):
    """
    반환값: ('added'|'replaced'|'skipped'|'error'|'no_head', 메시지)
    """
    url_path = get_url_path(filepath)
    if url_path is None:
        return ('skipped', '제외 대상')

    full_url = BASE_URL + url_path

    try:
        with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
            content = f.read()
    except Exception as e:
        return ('error', f'읽기 실패: {e}')

    # <head> 없으면 스킵
    if not re.search(r'<head', content, re.IGNORECASE):
        return ('no_head', '<head> 태그 없음 — 스킵')

    if has_canonical(content):
        new_content = replace_canonical(content, full_url)
        action = 'replaced'
        msg = f'canonical 교체 → {full_url}'
    else:
        new_content = insert_canonical(content, full_url)
        action = 'added'
        msg = f'canonical 추가 → {full_url}'

    if content == new_content:
        return ('skipped', '변경 없음')

    if not dry_run:
        # 백업
        backup_path = os.path.join(BACKUP_DIR, os.path.relpath(filepath, SCRIPT_DIR))
        os.makedirs(os.path.dirname(backup_path), exist_ok=True)
        shutil.copy2(filepath, backup_path)
        # 저장
        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(new_content)

    return (action, msg)

def find_html_files():
    """스크립트 폴더 내 모든 HTML 파일 탐색"""
    html_files = []
    for root, dirs, files in os.walk(SCRIPT_DIR):
        # 백업 폴더, 숨김 폴더 제외
        dirs[:] = [d for d in dirs if not d.startswith('_canonical_backup') and not d.startswith('.')]
        for name in files:
            if name.lower().endswith(('.html', '.htm')):
                html_files.append(os.path.join(root, name))
    return html_files

def run(dry_run):
    files = find_html_files()
    total = len(files)
    print(f"\n{'[드라이런 — 파일 실제로 수정 안 함]' if dry_run else '[실제 실행]'}")
    print(f"HTML 파일 {total}개 발견\n")

    counts = {'added': 0, 'replaced': 0, 'skipped': 0, 'no_head': 0, 'error': 0}
    errors = []
    log_lines = []

    for i, filepath in enumerate(files, 1):
        action, msg = process_file(filepath, dry_run=dry_run)
        counts[action] += 1
        rel = os.path.relpath(filepath, SCRIPT_DIR)
        log_line = f"[{action.upper()}] {rel} — {msg}"
        log_lines.append(log_line)

        if action == 'error':
            errors.append(log_line)

        # 진행상황 출력 (100개마다)
        if i % 100 == 0 or i == total:
            print(f"  진행: {i}/{total} | 추가 {counts['added']} | 교체 {counts['replaced']} | 에러 {counts['error']}")

    # 결과 요약
    print(f"""
{'='*50}
✅ 완료 요약
{'='*50}
  canonical 추가 : {counts['added']}개
  canonical 교체 : {counts['replaced']}개
  <head> 없어서 스킵 : {counts['no_head']}개
  변경 없음 스킵 : {counts['skipped']}개
  에러 : {counts['error']}개
{'='*50}""")

    if errors:
        print("\n⚠️  에러 발생 파일:")
        for e in errors:
            print(f"  {e}")

    if not dry_run:
        print(f"\n📁 원본 백업 위치: {BACKUP_DIR}")
        # 로그 파일 저장
        with open(LOG_FILE, 'w', encoding='utf-8') as f:
            f.write(f"실행 시각: {datetime.now()}\n")
            f.write(f"BASE_URL: {BASE_URL}\n\n")
            f.write('\n'.join(log_lines))
        print(f"📄 상세 로그: {LOG_FILE}")

    return counts

# ── 메인 ──────────────────────────────────────────────
if __name__ == '__main__':
    print("=" * 50)
    print("  topeduprep.uk canonical 태그 자동 삽입기")
    print("=" * 50)
    print(f"  대상 폴더: {SCRIPT_DIR}")
    print(f"  Base URL : {BASE_URL}")

    # 1. 드라이런
    print("\n[STEP 1] 드라이런 실행 중 (파일 수정 없음)...")
    counts = run(dry_run=True)

    if counts['added'] + counts['replaced'] == 0:
        print("\n처리할 파일이 없습니다. 종료합니다.")
        exit()

    # 2. 확인
    print(f"\n위 내용으로 실제 파일 {counts['added'] + counts['replaced']}개를 수정합니다.")
    print("원본은 자동 백업됩니다.")
    answer = input("\n진행하려면 'yes' 입력 후 엔터: ").strip().lower()

    if answer == 'yes':
        print("\n[STEP 2] 실제 실행 중...")
        run(dry_run=False)
        print("\n🎉 완료! Search Console에서 sitemap.xml 재제출하세요.")
    else:
        print("\n취소되었습니다. 파일은 수정되지 않았습니다.")
