#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
不動產投資組合視覺化資料去識別化工具

功能：
1. 將大樓名稱改為匿名代碼（A棟、B棟等）
2. 將縣市名稱改為匿名代碼（A市、B市等）
3. 將地址去識別化
4. 將座標進行隨機偏移
5. 將客戶名稱去識別化
6. 將估價師事務所名稱去識別化
"""

import os
import re
import random
from pathlib import Path

class PropertyDataAnonymizer:
    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.building_mapping = {}
        self.building_counter = 1

        # 估價師事務所對應表
        self.appraiser_mapping = {}
        self.appraiser_counter = 1

        # 客戶名稱對應
        self.client_mapping = {
            '新光人壽': 'XX集團',
            '新光': 'XX',
        }

    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:
            # 使用字母代碼：估價師A、估價師B等
            letter = chr(64 + self.appraiser_counter)  # A=65
            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)
            # 偏移範圍：±0.01 到 ±0.05（約1-5公里）
            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, address):
        """地址去識別化"""
        # 先替換縣市
        for city, anon_city in self.city_mapping.items():
            address = address.replace(city, anon_city)

        # 替換路名和門牌號碼
        # 例如：忠孝西路一段66號 → OOO路X段Y號
        address = re.sub(r'[^市縣區鄉鎮里村][\u4e00-\u9fa5]+路', 'OOO路', address)
        address = re.sub(r'[^市縣區鄉鎮里村][\u4e00-\u9fa5]+街', 'OOO街', address)
        address = re.sub(r'一段|二段|三段|四段|五段|六段|七段|八段|九段|十段', 'X段', address)
        address = re.sub(r'\d+號', 'Y號', address)
        address = re.sub(r'\d+樓', 'Z樓', address)

        return address

    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. 替換客戶名稱
        for client, anon_client in self.client_mapping.items():
            content = content.replace(client, anon_client)

        # 2. 替換縣市名稱
        for city, anon_city in self.city_mapping.items():
            content = content.replace(city, anon_city)

        # 3. 替換地址（在替換縣市之後）
        # 找出所有地址模式並替換
        address_pattern = r'[A-Z]市[^<>]{5,30}號'
        addresses = re.findall(address_pattern, content)
        for addr in set(addresses):
            anon_addr = self.anonymize_address(addr)
            content = content.replace(addr, anon_addr)

        # 4. 替換座標（找出 JavaScript 中的經緯度數據）
        # 模式：[緯度, 經度] 或 latitude: 數字, longitude: 數字
        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)

        # 5. 替換大樓名稱（需要識別常見的大樓名稱模式）
        # 這部分比較複雜，因為大樓名稱可能出現在各種地方
        # 我們先找出一些常見模式
        building_patterns = [
            r'([^<>]{2,10}大樓)',
            r'([^<>]{2,10}廣場)',
            r'([^<>]{2,10}大廈)',
            r'([^<>]{2,10}商場)',
            r'([^<>]{2,10}中心)',
        ]

        for pattern in building_patterns:
            buildings = re.findall(pattern, content)
            for building in set(buildings):
                if building not in ['XX集團']:  # 避免替換已經匿名化的名稱
                    anon_building = self.get_building_code(building)
                    content = content.replace(building, anon_building)

        # 6. 替換估價師事務所名稱
        # 常見的估價師事務所名稱模式
        appraiser_keywords = ['估價', '不動產', '鑑定', '聯合', '事務所']
        # 這裡我們需要更具體的名單，從 Gemini 分析結果中提取
        known_appraisers = ['麗業', '尚上', '中徵', '瑞普', 'DTZ', '信義', '歐亞', '台灣', '戴德梁行']

        for appraiser in known_appraisers:
            if appraiser in content:
                anon_appraiser = self.get_appraiser_code(appraiser)
                content = content.replace(appraiser, anon_appraiser)

        # 寫回檔案
        if content != original_content:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
            print(f"  [OK] 已更新")
        else:
            print(f"  [-] 無需更新")

    def process_directory(self, dir_path):
        """處理整個目錄"""
        dir_path = Path(dir_path)
        html_files = list(dir_path.glob('*.html'))

        print(f"\n開始處理 {len(html_files)} 個 HTML 檔案...")
        print("=" * 60)

        for html_file in html_files:
            self.process_html_file(html_file)

        print("=" * 60)
        print("\n處理完成！")
        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 = PropertyDataAnonymizer()
    anonymizer.process_directory(viz_dir)

    print("\n[OK] 所有檔案處理完成！")
    print(f"[OK] 視覺化檔案位置: {viz_dir}")
    print(f"[OK] 對應表位置: {script_dir / 'anonymization_mapping.txt'}")
