#!/usr/bin/env python3
"""
rog_team テーブル専用移行スクリプト (構造変換対応)
old_rogdb の rog_team から rogdb の rog_team へ構造変換を行いながらデータ移行
"""

import os
import sys
import psycopg2
from datetime import datetime, timezone
import logging

# ログ設定
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# データベース設定
OLD_ROGDB_CONFIG = {
    'host': os.getenv('OLD_ROGDB_HOST', 'postgres-db'),
    'database': os.getenv('OLD_ROGDB_NAME', 'old_rogdb'),
    'user': os.getenv('OLD_ROGDB_USER', 'admin'),
    'password': os.getenv('OLD_ROGDB_PASSWORD', 'admin123456'),
    'port': int(os.getenv('OLD_ROGDB_PORT', 5432))
}

ROGDB_CONFIG = {
    'host': os.getenv('ROGDB_HOST', 'postgres-db'),
    'database': os.getenv('ROGDB_NAME', 'rogdb'),
    'user': os.getenv('ROGDB_USER', 'admin'),
    'password': os.getenv('ROGDB_PASSWORD', 'admin123456'),
    'port': int(os.getenv('ROGDB_PORT', 5432))
}

class RogTeamMigrator:
    """rog_team テーブル専用移行クラス"""
    
    def __init__(self):
        self.old_conn = None
        self.new_conn = None
        self.old_cursor = None
        self.new_cursor = None
        self.default_event_id = None
        
    def connect_databases(self):
        """データベース接続"""
        try:
            logger.info("データベースに接続中...")
            self.old_conn = psycopg2.connect(**OLD_ROGDB_CONFIG)
            self.new_conn = psycopg2.connect(**ROGDB_CONFIG)
            
            self.old_conn.autocommit = True
            self.new_conn.autocommit = False
            
            self.old_cursor = self.old_conn.cursor()
            self.new_cursor = self.new_conn.cursor()
            
            logger.info("✅ データベース接続成功")
            return True
            
        except Exception as e:
            logger.error(f"❌ データベース接続エラー: {e}")
            return False
    
    def close_connections(self):
        """データベース接続クローズ"""
        try:
            if self.old_cursor:
                self.old_cursor.close()
            if self.new_cursor:
                self.new_cursor.close()
            if self.old_conn:
                self.old_conn.close()
            if self.new_conn:
                self.new_conn.close()
            logger.info("データベース接続をクローズしました")
        except Exception as e:
            logger.warning(f"接続クローズ時の警告: {e}")
    
    def get_team_zekken_and_event(self, team_id):
        """team_idから最新のrog_entryのzekken_numberとevent_idを取得"""
        try:
            # 旧DBのrog_entryから該当team_idの最新レコードを取得
            self.old_cursor.execute("""
                SELECT zekken_number, event_id, date
                FROM rog_entry 
                WHERE team_id = %s 
                AND zekken_number IS NOT NULL 
                AND event_id IS NOT NULL
                ORDER BY date DESC, id DESC
                LIMIT 1
            """, (team_id,))
            
            result = self.old_cursor.fetchone()
            
            if result:
                zekken_number, event_id, entry_date = result
                logger.debug(f"team_id {team_id}: zekken_number={zekken_number}, event_id={event_id}, date={entry_date}")
                return str(zekken_number), event_id
            else:
                # rog_entryにレコードがない場合はデフォルト値を返す
                logger.warning(f"team_id {team_id}: rog_entryにレコードが見つかりません")
                return '', self.default_event_id
                
        except Exception as e:
            logger.error(f"team_id {team_id} のzekken_number/event_id取得エラー: {e}")
            return '', self.default_event_id
    
    def get_default_event_id(self):
        """デフォルトのevent_idを取得または作成"""
        try:
            # 既存のイベントを探す
            self.new_cursor.execute("""
                SELECT id FROM rog_newevent2 
                WHERE event_name LIKE '%移行%' OR event_name LIKE '%default%'
                ORDER BY id LIMIT 1
            """)
            result = self.new_cursor.fetchone()
            
            if result:
                event_id = result[0]
                logger.info(f"既存のデフォルトイベントを使用: event_id = {event_id}")
                return event_id
            
            # なければ最初のイベントを使用
            self.new_cursor.execute("""
                SELECT id FROM rog_newevent2 
                ORDER BY id LIMIT 1
            """)
            result = self.new_cursor.fetchone()
            
            if result:
                event_id = result[0]
                logger.info(f"最初のイベントをデフォルトとして使用: event_id = {event_id}")
                return event_id
            
            # イベントがない場合はエラー
            logger.error("❌ rog_newevent2 テーブルにイベントが存在しません")
            return None
            
        except Exception as e:
            logger.error(f"❌ デフォルトevent_id取得エラー: {e}")
            return None
    
    def get_category_mapping(self):
        """カテゴリIDのマッピングを確認"""
        try:
            # 旧DBのカテゴリ
            self.old_cursor.execute("SELECT id, category_name FROM rog_newcategory ORDER BY id")
            old_categories = dict(self.old_cursor.fetchall())
            
            # 新DBのカテゴリ
            self.new_cursor.execute("SELECT id, category_name FROM rog_newcategory ORDER BY id")
            new_categories = dict(self.new_cursor.fetchall())
            
            logger.info(f"旧DB カテゴリ: {old_categories}")
            logger.info(f"新DB カテゴリ: {new_categories}")
            
            # 名前ベースでマッピング作成
            category_mapping = {}
            for old_id, old_name in old_categories.items():
                for new_id, new_name in new_categories.items():
                    if old_name == new_name:
                        category_mapping[old_id] = new_id
                        break
                else:
                    # マッチしない場合は最初のカテゴリを使用
                    if new_categories:
                        category_mapping[old_id] = min(new_categories.keys())
                        logger.warning(f"カテゴリマッピング失敗 - デフォルト使用: {old_id} -> {category_mapping[old_id]}")
            
            return category_mapping
            
        except Exception as e:
            logger.error(f"❌ カテゴリマッピング取得エラー: {e}")
            return {}
    
    def convert_team_record(self, old_record, category_mapping):
        """旧レコードを新レコード形式に変換"""
        old_id, old_team_name, old_category_id, old_owner_id = old_record
        
        # team_idから最新のzekken_numberとevent_idを取得
        zekken_number, event_id = self.get_team_zekken_and_event(old_id)
        
        # 新しいレコード作成
        new_record = {
            'id': old_id,
            'team_name': old_team_name,
            'category_id': category_mapping.get(old_category_id, old_category_id),
            'owner_id': old_owner_id,
            # 新しいフィールドにデフォルト値を設定
            'class_name': '',  # 空文字列
            'event_id': event_id,  # rog_entryから取得したevent_id
            'location': None,  # PostGIS座標は後で設定可能
            'password': '',  # パスワードなし
            'trial': False,  # 本番チーム
            'zekken_number': zekken_number,  # rog_entryから取得したzekken_number
            'created_at': datetime.now(timezone.utc),
            'updated_at': datetime.now(timezone.utc)
        }
        
        return new_record
    
    def migrate_rog_team(self):
        """rog_team テーブルのデータ移行"""
        logger.info("=" * 60)
        logger.info("rog_team テーブル構造変換移行開始")
        logger.info("=" * 60)
        
        try:
            # デフォルトevent_id取得
            self.default_event_id = self.get_default_event_id()
            if not self.default_event_id:
                return False
            
            # カテゴリマッピング取得
            category_mapping = self.get_category_mapping()
            
            # 旧データ取得
            logger.info("旧rog_teamデータを取得中...")
            self.old_cursor.execute("""
                SELECT id, team_name, category_id, owner_id 
                FROM rog_team 
                ORDER BY id
            """)
            old_records = self.old_cursor.fetchall()
            
            if not old_records:
                logger.info("✅ 移行対象データがありません")
                return True
            
            logger.info(f"移行対象レコード数: {len(old_records)}件")
            
            # 統計情報
            inserted_count = 0
            updated_count = 0
            error_count = 0
            zekken_resolved_count = 0
            constraint_avoided_count = 0
            
            # レコード別処理
            for i, old_record in enumerate(old_records):
                try:
                    # レコード変換
                    new_record = self.convert_team_record(old_record, category_mapping)
                    team_id = new_record['id']
                    
                    # zekken_number解決統計
                    if new_record['zekken_number']:
                        zekken_resolved_count += 1
                    
                    # 既存レコード確認（IDベース）
                    self.new_cursor.execute(
                        "SELECT COUNT(*) FROM rog_team WHERE id = %s",
                        (team_id,)
                    )
                    exists_by_id = self.new_cursor.fetchone()[0] > 0
                    
                    # 重複制約確認（zekken_number + event_id の組み合わせ）
                    if new_record['zekken_number']:  # zekken_numberが空でない場合のみチェック
                        self.new_cursor.execute(
                            "SELECT COUNT(*) FROM rog_team WHERE zekken_number = %s AND event_id = %s",
                            (new_record['zekken_number'], new_record['event_id'])
                        )
                        exists_by_constraint = self.new_cursor.fetchone()[0] > 0
                        
                        if exists_by_constraint and not exists_by_id:
                            # 制約違反が発生する場合は、zekken_numberを空にしてデフォルトevent_idを使用
                            logger.warning(f"Team ID {team_id}: zekken_number制約回避のため空文字に変更")
                            new_record['zekken_number'] = ''
                            new_record['event_id'] = self.default_event_id
                            constraint_avoided_count += 1
                    
                    if exists_by_id:
                        # UPDATE処理
                        update_query = """
                            UPDATE rog_team SET
                                team_name = %s,
                                category_id = %s,
                                owner_id = %s,
                                class_name = %s,
                                event_id = %s,
                                location = %s,
                                password = %s,
                                trial = %s,
                                zekken_number = %s,
                                updated_at = %s
                            WHERE id = %s
                        """
                        
                        self.new_cursor.execute(update_query, (
                            new_record['team_name'],
                            new_record['category_id'],
                            new_record['owner_id'],
                            new_record['class_name'],
                            new_record['event_id'],
                            new_record['location'],
                            new_record['password'],
                            new_record['trial'],
                            new_record['zekken_number'],
                            new_record['updated_at'],
                            team_id
                        ))
                        updated_count += 1
                        
                    else:
                        # INSERT処理
                        insert_query = """
                            INSERT INTO rog_team (
                                id, team_name, category_id, owner_id,
                                class_name, event_id, location, password,
                                trial, zekken_number, created_at, updated_at
                            ) VALUES (
                                %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
                            )
                        """
                        
                        self.new_cursor.execute(insert_query, (
                            new_record['id'],
                            new_record['team_name'],
                            new_record['category_id'],
                            new_record['owner_id'],
                            new_record['class_name'],
                            new_record['event_id'],
                            new_record['location'],
                            new_record['password'],
                            new_record['trial'],
                            new_record['zekken_number'],
                            new_record['created_at'],
                            new_record['updated_at']
                        ))
                        inserted_count += 1
                    
                    # 進捗表示
                    if (i + 1) % 50 == 0:
                        self.new_conn.commit()
                        logger.info(f"  進捗: {i + 1}/{len(old_records)} 件処理完了")
                
                except Exception as e:
                    error_count += 1
                    logger.error(f"  レコード処理エラー (ID: {old_record[0]}): {e}")
                    
                    # トランザクションロールバック
                    try:
                        self.new_conn.rollback()
                    except:
                        pass
                    
                    if error_count > 10:
                        logger.error("❌ エラー数が上限を超えました")
                        break
            
            # 最終コミット
            self.new_conn.commit()
            
            # 結果サマリー
            logger.info("=" * 60)
            logger.info("rog_team 移行完了")
            logger.info("=" * 60)
            logger.info(f"挿入: {inserted_count}件")
            logger.info(f"更新: {updated_count}件")
            logger.info(f"エラー: {error_count}件")
            logger.info(f"zekken_number解決: {zekken_resolved_count}件")
            logger.info(f"制約回避: {constraint_avoided_count}件")
            logger.info(f"総処理: {len(old_records)}件")
            
            if error_count == 0:
                logger.info("✅ rog_team移行が正常に完了しました！")
                return True
            else:
                logger.warning(f"⚠️  {error_count}件のエラーがありました")
                return False
            
        except Exception as e:
            logger.error(f"❌ rog_team移行エラー: {e}")
            try:
                self.new_conn.rollback()
            except:
                pass
            return False
    
    def run(self):
        """移行実行"""
        try:
            if not self.connect_databases():
                return False
            
            return self.migrate_rog_team()
        
        finally:
            self.close_connections()

def main():
    """メイン処理"""
    logger.info("rog_team テーブル構造変換移行スクリプト")
    
    migrator = RogTeamMigrator()
    success = migrator.run()
    
    if success:
        logger.info("🎉 移行が正常に完了しました！")
    else:
        logger.error("💥 移行中にエラーが発生しました")
    
    sys.exit(0 if success else 1)

if __name__ == "__main__":
    main()
