#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
不動產投資組合視覺化資料去識別化工具 v2.0

改進：
1. 更徹底的地址資訊處理
2. 移除季度和年份資訊
3. 通用化標題
4. 更完整的路名、街名處理
"""

import os
import re
import random
from pathlib import Path

class PropertyDataAnonymizerV2:
    def __init__(self):
        # 縣市對應表
        self.city_mapping = {
            '台北市': 'A市',
            '新北市': 'B市',
            '桃園市': 'C市',
            '新竹縣': 'D縣',
            '新竹市': 'E市',
            '苗栗縣': 'F縣',
            '台中市': 'G市',
            '彰化縣': 'H縣',
            '南投縣': 'I縣',
            '雲林縣': 'J縣',
            '嘉義縣': 'K縣',
            '嘉義市': 'L市',
            '台南市': 'M市',
            '高雄市': 'N市',
            '屏東縣': 'O縣',
            '宜蘭縣': 'P縣',
            '花蓮縣': 'Q縣',
            '台東縣': 'R縣',
            '澎湖縣': 'S縣',
            '金門縣': 'T縣',
            '連江縣': 'U縣',
        }

        # 常見路名（需要替換的）
        self.road_names = [
            '忠孝', '仁愛', '信義', '和平', '南京', '民權', '民生', '松江',
            '中山', '建國', '復興', '敦化', '光復', '基隆', '羅斯福', '新生',
            '承德', '重慶', '延平', '西門', '漢口', '武昌', '中華', '環河',
            '博愛', '衡陽', '懷寧', '公園', '中正', '愛國', '杭州', '金山',
            '成功', '中興', '文化', '民族', '三民', '四維', '五福', '六合',
            '七賢', '八德', '九如', '十全', '建工', '建軍', '自由', '青年',
        ]

        # 大樓名稱對應表（動態生成）
        self.building_mapping = {}
        self.building_counter = 1

        # 估價師事務所對應表
        self.appraiser_mapping = {}
        self.appraiser_counter = 1

        # 客戶名稱對應
        self.client_mapping = {
            '新光人壽': 'XX集團',
            '新光': 'XX',
        }

        # 時間資訊替換
        self.time_replacements = {
            '2025Q4': '20XX',
            '2025': '20XX',
            'Q4': '',
            '第四季': '',
        }

    def get_building_code(self, building_name):
        """取得大樓匿名代碼"""
        if building_name not in self.building_mapping:
            self.building_mapping[building_name] = f"標的{self.building_counter:03d}"
            self.building_counter += 1
        return self.building_mapping[building_name]

    def get_appraiser_code(self, appraiser_name):
        """取得估價師匿名代碼"""
        if appraiser_name not in self.appraiser_mapping:
            letter = chr(64 + self.appraiser_counter)
            self.appraiser_mapping[appraiser_name] = f"估價師{letter}"
            self.appraiser_counter += 1
        return self.appraiser_mapping[appraiser_name]

    def offset_coordinate(self, coord_str, is_latitude=True):
        """座標隨機偏移"""
        try:
            coord = float(coord_str)
            offset = random.uniform(-0.05, 0.05)
            new_coord = coord + offset

            if is_latitude:
                new_coord = max(21.5, min(25.5, new_coord))
            else:
                new_coord = max(120.0, min(122.5, new_coord))

            return f"{new_coord:.6f}"
        except:
            return coord_str

    def anonymize_address(self, text):
        """地址去識別化（更徹底）"""
        # 先替換縣市
        for city, anon_city in self.city_mapping.items():
            text = text.replace(city, anon_city)

        # 替換所有路名
        for road_name in self.road_names:
            text = re.sub(f'{road_name}[東西南北]?路', 'OOO路', text)
            text = re.sub(f'{road_name}[東西南北]?街', 'OOO街', text)

        # 替換一般路名模式
        text = re.sub(r'[\u4e00-\u9fa5]{2,6}[東西南北]?路', 'OOO路', text)
        text = re.sub(r'[\u4e00-\u9fa5]{2,6}[東西南北]?街', 'OOO街', text)

        # 替換段數
        text = re.sub(r'[一二三四五六七八九十]+段', 'X段', text)

        # 替換門牌號碼
        text = re.sub(r'\d+號', 'Y號', text)
        text = re.sub(r'\d+樓', 'Z樓', text)
        text = re.sub(r'\d+巷', 'A巷', text)
        text = re.sub(r'\d+弄', 'B弄', text)

        # 替換區、里、村
        text = re.sub(r'[\u4e00-\u9fa5]{2,4}區', 'XX區', text)
        text = re.sub(r'[\u4e00-\u9fa5]{2,4}里', 'XX里', text)
        text = re.sub(r'[\u4e00-\u9fa5]{2,4}村', 'XX村', text)

        return text

    def process_html_file(self, file_path):
        """處理單一HTML檔案"""
        print(f"處理檔案: {file_path.name}")

        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()

        original_content = content

        # 1. 替換標題和時間資訊
        content = content.replace('XX集團 2025Q4 投資性不動產覆核', '不動產投資組合分析系統 (Demo)')
        content = content.replace('XX集團 2025Q4', '投資組合 Demo')
        content = content.replace('2025Q4', '20XX')
        content = content.replace('2025', '20XX')

        # 2. 替換客戶名稱
        for client, anon_client in self.client_mapping.items():
            content = content.replace(client, anon_client)

        # 3. 替換縣市名稱
        for city, anon_city in self.city_mapping.items():
            content = content.replace(city, anon_city)

        # 4. 徹底處理地址（多次處理確保完整）
        content = self.anonymize_address(content)

        # 再次處理可能殘留的地址
        content = self.anonymize_address(content)

        # 5. 替換座標
        def replace_coordinates(match):
            lat = match.group(1)
            lng = match.group(2)
            new_lat = self.offset_coordinate(lat, is_latitude=True)
            new_lng = self.offset_coordinate(lng, is_latitude=False)
            return f"[{new_lat}, {new_lng}]"

        content = re.sub(r'\[(\d+\.\d+),\s*(\d+\.\d+)\]', replace_coordinates, content)

        # 6. 替換大樓名稱
        building_patterns = [
            r'([^<>]{2,10}大樓)',
            r'([^<>]{2,10}廣場)',
            r'([^<>]{2,10}大廈)',
            r'([^<>]{2,10}商場)',
            r'([^<>]{2,10}中心)',
        ]

        # 保護關鍵字清單（不要替換的詞）
        protected_keywords = [
            'XX集團', 'XX區', 'XX里', 'XX村', 'XX市', 'XX縣',
            '金額區間', '差異率', '估價單位', '投資組合',
        ]

        for pattern in building_patterns:
            buildings = re.findall(pattern, content)
            for building in set(buildings):
                # 檢查是否包含保護關鍵字
                should_protect = False
                for keyword in protected_keywords:
                    if keyword in building:
                        should_protect = True
                        break

                if not should_protect:
                    anon_building = self.get_building_code(building)
                    content = content.replace(building, anon_building)

        # 7. 替換估價師事務所
        known_appraisers = [
            '麗業', '尚上', '中徵', '瑞普', 'DTZ', '信義', '歐亞',
            '台灣', '戴德梁行', '第一', '仲量聯行', '世邦魏理仕',
            '高力', '萊坊', '太平', '聯合', '國際', '中華',
        ]

        for appraiser in known_appraisers:
            # 避免替換已經匿名的詞
            if appraiser in content and '估價師' not in appraiser:
                anon_appraiser = self.get_appraiser_code(appraiser)
                # 只替換在估價師上下文中的出現
                content = re.sub(f'{appraiser}(?=不動產|估價|鑑定|事務所)', anon_appraiser, content)
                content = content.replace(f'{appraiser}', anon_appraiser)

        # 8. 最後再次清理可能殘留的資訊
        # 不要移除所有 HTML 註解，因為可能包含必要的程式碼
        # content = re.sub(r'<!--.*?-->', '', content, flags=re.DOTALL)

        # 寫回檔案
        if content != original_content:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
            print(f"  [OK] 已更新")
        else:
            print(f"  [-] 無需更新")

        return content != original_content

    def process_directory(self, dir_path):
        """處理整個目錄"""
        dir_path = Path(dir_path)
        html_files = list(dir_path.glob('*.html'))

        # 排除備份檔
        html_files = [f for f in html_files if '.bak' not in f.name]

        print(f"\n開始處理 {len(html_files)} 個 HTML 檔案...")
        print("=" * 60)

        updated_count = 0
        for html_file in html_files:
            if self.process_html_file(html_file):
                updated_count += 1

        print("=" * 60)
        print(f"\n處理完成！更新了 {updated_count} 個檔案")
        print(f"\n對應表統計:")
        print(f"  - 縣市: {len(self.city_mapping)} 個")
        print(f"  - 大樓: {len(self.building_mapping)} 個")
        print(f"  - 估價師: {len(self.appraiser_mapping)} 個")

        self.save_mapping_table(dir_path.parent / 'anonymization_mapping.txt')

    def save_mapping_table(self, output_path):
        """儲存對應表"""
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write("=" * 60 + "\n")
            f.write("去識別化對應表（僅供內部參考，請勿外流）\n")
            f.write("=" * 60 + "\n\n")

            f.write("【縣市對應】\n")
            for original, anon in sorted(self.city_mapping.items()):
                f.write(f"  {original:10s} → {anon}\n")

            f.write("\n【大樓對應】\n")
            for original, anon in sorted(self.building_mapping.items(), key=lambda x: x[1]):
                f.write(f"  {original:20s} → {anon}\n")

            f.write("\n【估價師對應】\n")
            for original, anon in sorted(self.appraiser_mapping.items(), key=lambda x: x[1]):
                f.write(f"  {original:15s} → {anon}\n")

            f.write("\n【客戶對應】\n")
            for original, anon in self.client_mapping.items():
                f.write(f"  {original:15s} → {anon}\n")

        print(f"\n對應表已儲存至: {output_path}")


if __name__ == '__main__':
    random.seed(42)

    script_dir = Path(__file__).parent
    viz_dir = script_dir / 'visualization'

    if not viz_dir.exists():
        print(f"錯誤: 找不到 visualization 目錄: {viz_dir}")
        exit(1)

    anonymizer = PropertyDataAnonymizerV2()
    anonymizer.process_directory(viz_dir)

    print("\n[OK] 所有檔案處理完成！")
    print(f"[OK] 視覺化檔案位置: {viz_dir}")
    print(f"[OK] 對應表位置: {script_dir / 'anonymization_mapping.txt'}")
