#!/usr/bin/env python
"""
CSVファイルからチーム情報をデータベースに登録するスクリプト
CPLIST/input/teams2025.csv から以下の手順でデータベーステーブルに書き込む

実行方法:
python register_teams_from_csv.py --event_code <event_code>

例:
python register_teams_from_csv.py --event_code GIFU2025
"""

import os
import sys
import django
import argparse
import csv
from datetime import datetime, date, timedelta
from decimal import Decimal

# Django設定
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
django.setup()

from django.contrib.auth import get_user_model
from django.db import transaction
from django.utils import timezone
from rog.models import (
    CustomUser, NewEvent2, NewCategory, Team, Member, Entry, EntryMember
)

User = get_user_model()

class TeamRegistrationProcessor:
    def __init__(self, event_code, dry_run=False):
        self.event_code = event_code
        self.dry_run = dry_run
        self.event = None
        self.categories = {}
        self.stats = {
            'users_created': 0,
            'users_updated': 0,
            'teams_created': 0,
            'members_created': 0,
            'entries_created': 0,
            'participations_created': 0,
            'errors': []
        }
        
    def initialize(self):
        """イベントとカテゴリの初期化"""
        if self.dry_run:
            print("DRY RUN MODE: データベースの変更は行いません")
            
        try:
            self.event = NewEvent2.objects.get(event_code=self.event_code)
            print(f"イベント取得: {self.event.event_name} ({self.event_code})")
        except NewEvent2.DoesNotExist:
            if self.dry_run:
                print(f"DRY RUN: Event with code '{self.event_code}' would be searched")
                # ダミーイベントオブジェクトを作成
                class DummyEvent:
                    def __init__(self):
                        self.event_name = f"Dummy Event for {self.event_code}"
                        self.event_code = self.event_code
                self.event = DummyEvent()
                return
            else:
                raise ValueError(f"Event with code '{self.event_code}' not found")
        
        # カテゴリ情報をプリロード
        for category in NewCategory.objects.all():
            hours = int(category.duration.total_seconds() // 3600)
            key = (category.category_name, hours)
            self.categories[key] = category
            
        print(f"利用可能なカテゴリ: {list(self.categories.keys())}")
    
    def parse_csv_row(self, row):
        """CSV行をパース"""
        if len(row) < 20:
            raise ValueError(f"不正な行形式: {len(row)} columns found, expected at least 20")
        
        data = {
            'department_count': row[0].strip(),
            'hours': row[1].strip(),
            'department': row[2].strip(),
            'team_name': row[3].strip(),
            'email': row[4].strip(),
            'password': row[5].strip(),
            'phone': row[6].strip(),
            'members': []
        }
        
        # メンバー情報を解析（最大7名）
        for i in range(7):
            name_idx = 7 + i * 2
            birth_idx = 8 + i * 2
            
            if name_idx < len(row) and birth_idx < len(row):
                name = row[name_idx].strip() if row[name_idx] else None
                birth_str = row[birth_idx].strip() if row[birth_idx] else None
                
                if name and birth_str:
                    try:
                        # 誕生日の解析（複数フォーマット対応）
                        birth_date = None
                        for fmt in ['%Y/%m/%d', '%Y-%m-%d', '%Y/%m/%d ']:
                            try:
                                birth_date = datetime.strptime(birth_str.strip(), fmt).date()
                                break
                            except ValueError:
                                continue
                        
                        if birth_date:
                            data['members'].append({
                                'name': name,
                                'birth_date': birth_date
                            })
                        else:
                            print(f"警告: 誕生日の形式が不正です: {birth_str}")
                    except Exception as e:
                        print(f"警告: メンバー情報の解析エラー: {e}")
        
        return data
    
    def get_or_create_category(self, department, hours):
        """カテゴリを取得または作成"""
        try:
            hours_int = int(hours)
        except ValueError:
            hours_int = 5  # デフォルト
        
        # 既存カテゴリから検索
        key = (department, hours_int)
        if key in self.categories:
            return self.categories[key]
        
        # 一般的なカテゴリ名でマッピング
        category_mappings = {
            '一般': 'General',
            'ファミリー': 'Family',
            '男性ソロ': 'Solo Male',
            '女性ソロ': 'Solo Female',
        }
        
        mapped_name = category_mappings.get(department, department)
        key_mapped = (mapped_name, hours_int)
        if key_mapped in self.categories:
            return self.categories[key_mapped]
        
        # 時間だけでマッチング（一般カテゴリとして）
        for (cat_name, cat_hours), category in self.categories.items():
            if cat_hours == hours_int and cat_name in ['General', '一般']:
                return category
        
        # 新しいカテゴリを作成
        print(f"新しいカテゴリを作成: {department} ({hours_int}時間)")
        
        if self.dry_run:
            print(f"DRY RUN: カテゴリ作成 - {department} ({hours_int}時間)")
            # ダミーカテゴリオブジェクトを作成
            class DummyCategory:
                def __init__(self):
                    self.category_name = department
                    self.category_number = len(self.categories) + 1
                    self.duration = timedelta(hours=hours_int)
                    self.num_of_member = 7
                    self.family = (department == 'ファミリー')
                    self.female = (department == '女性ソロ')
                    self.trial = False
            
            category = DummyCategory()
        else:
            category = NewCategory.objects.create(
                category_name=department,
                category_number=len(self.categories) + 1,
                duration=timedelta(hours=hours_int),
                num_of_member=7,  # 最大7名
                family=(department == 'ファミリー'),
                female=(department == '女性ソロ'),
                trial=False
            )
        
        self.categories[key] = category
        return category
    
    def process_user(self, data):
        """ユーザーの処理（2-1）"""
        email = data['email']
        password = data['password']
        team_name = data['team_name']
        
        # ゼッケン番号は部門別数を使用
        zekken_number = data['department_count']
        
        if self.dry_run:
            print(f"DRY RUN: ユーザー処理 - {email}")
            print(f"  - チーム名: {team_name}")
            print(f"  - ゼッケン番号: {zekken_number}")
            
            # ダミーユーザーオブジェクトを返す
            class DummyUser:
                def __init__(self):
                    self.email = email
                    self.firstname = data['members'][0]['name'] if data['members'] else 'Unknown'
                    self.lastname = ''
                    self.date_of_birth = data['members'][0]['birth_date'] if data['members'] else date.today()
                    self.female = False
                    self.zekken_number = zekken_number
                    self.event_code = self.event_code
                    self.team_name = team_name
            
            self.stats['users_created'] += 1
            return DummyUser()
        
        try:
            # 既存ユーザーを検索
            user = CustomUser.objects.get(email=email)
            
            # パスワードとその他の情報を更新
            user.set_password(password)
            user.event_code = self.event_code
            user.zekken_number = zekken_number
            user.team_name = team_name
            user.is_rogaining = True
            user.save()
            
            print(f"ユーザー更新: {email}")
            self.stats['users_updated'] += 1
            
        except CustomUser.DoesNotExist:
            # 新規ユーザー作成
            # メンバー情報から代表者の情報を取得
            first_member = data['members'][0] if data['members'] else None
            
            user = CustomUser.objects.create(
                email=email,
                firstname=first_member['name'] if first_member else 'Unknown',
                lastname='',
                date_of_birth=first_member['birth_date'] if first_member else date.today(),
                female=False,  # デフォルト
                group=data['department'],
                is_active=True,
                is_rogaining=True,
                zekken_number=zekken_number,
                event_code=self.event_code,
                team_name=team_name
            )
            user.set_password(password)
            user.save()
            
            print(f"ユーザー作成: {email}")
            self.stats['users_created'] += 1
        
        return user
    
    def create_dummy_users_for_members(self, data, main_user):
        """メンバー用ダミーユーザーを作成"""
        dummy_users = []
        
        for i, member_data in enumerate(data['members']):
            # メインユーザーをスキップ
            if i == 0:
                dummy_users.append(main_user)
                continue
            
            # ダミーメールアドレス生成
            dummy_email = f"dummy_{self.event_code}_{data['department_count']}_{i}@dummy.local"
            
            if self.dry_run:
                print(f"DRY RUN: ダミーユーザー作成 - {dummy_email}")
                print(f"  - 名前: {member_data['name']}")
                print(f"  - 誕生日: {member_data['birth_date']}")
                
                # ダミーユーザーオブジェクトを作成
                class DummyUser:
                    def __init__(self):
                        self.email = dummy_email
                        self.firstname = member_data['name']
                        self.lastname = ''
                        self.date_of_birth = member_data['birth_date']
                        self.female = False
                        self.event_code = self.event_code
                        self.team_name = data['team_name']
                
                dummy_users.append(DummyUser())
                continue
            
            try:
                # 既存のダミーユーザーを確認
                dummy_user = CustomUser.objects.get(email=dummy_email)
            except CustomUser.DoesNotExist:
                # ダミーユーザー作成
                dummy_user = CustomUser.objects.create(
                    email=dummy_email,
                    firstname=member_data['name'],
                    lastname='',
                    date_of_birth=member_data['birth_date'],
                    female=False,  # 名前から推測するかデフォルト
                    group=data['department'],
                    is_active=False,  # ダミーユーザーは非アクティブ
                    is_rogaining=True,
                    event_code=self.event_code,
                    team_name=data['team_name']
                )
                dummy_user.set_password('dummy123')
                dummy_user.save()
                
                print(f"ダミーユーザー作成: {dummy_email}")
            
            dummy_users.append(dummy_user)
        
        return dummy_users
    
    def process_team(self, data, owner, category):
        """チーム登録（2-2）"""
        team_name = data['team_name']
        zekken_number = data['department_count']
        
        if self.dry_run:
            print(f"DRY RUN: チーム作成 - {team_name}")
            print(f"  - ゼッケン番号: {zekken_number}")
            print(f"  - カテゴリ: {category.category_name if hasattr(category, 'category_name') else 'Unknown'}")
            print(f"  - オーナー: {owner.email}")
            
            # ダミーチームオブジェクトを作成
            class DummyTeam:
                def __init__(self, processor):
                    self.team_name = team_name
                    self.zekken_number = zekken_number
                    self.owner = owner
                    self.event = processor.event
                    self.password = data['password']
                    self.class_name = data['department']
            
            self.stats['teams_created'] += 1
            return DummyTeam(self)
        
        # 既存チームを確認
        try:
            team = Team.objects.get(
                team_name=team_name,
                event=self.event,
                zekken_number=zekken_number
            )
            print(f"既存チーム使用: {team_name}")
        except Team.DoesNotExist:
            # 新規チーム作成
            team = Team.objects.create(
                team_name=team_name,
                owner=owner,
                category=category,
                zekken_number=zekken_number,
                event=self.event,
                password=data['password'],
                class_name=data['department']
            )
            print(f"チーム作成: {team_name}")
            self.stats['teams_created'] += 1
        
        return team
    
    def process_members(self, data, team, users):
        """メンバー登録"""
        if self.dry_run:
            print(f"DRY RUN: メンバー登録 - {team.team_name}")
            for user in users:
                print(f"  - {user.firstname} ({user.email})")
                self.stats['members_created'] += 1
            return
        
        # 既存メンバーを削除（更新の場合）
        Member.objects.filter(team=team).delete()
        
        for user in users:
            member = Member.objects.create(
                team=team,
                user=user,
                firstname=user.firstname,
                lastname=user.lastname,
                date_of_birth=user.date_of_birth,
                female=user.female,
                is_temporary=True if user.email.startswith('dummy_') else False
            )
            print(f"メンバー追加: {user.firstname} to {team.team_name}")
            self.stats['members_created'] += 1
    
    def process_entry(self, team, category):
        """エントリー登録（2-3）"""
        if self.dry_run:
            print(f"DRY RUN: エントリー作成 - {team.team_name}")
            print(f"  - カテゴリ: {category.category_name if hasattr(category, 'category_name') else 'Unknown'}")
            print(f"  - ゼッケン番号: {team.zekken_number}")
            
            # ダミーエントリーオブジェクトを作成
            class DummyEntry:
                def __init__(self, processor):
                    self.team = team
                    self.event = processor.event
                    self.category = category
                    self.zekken_number = int(team.zekken_number)
                    self.is_active = True
            
            self.stats['entries_created'] += 1
            return DummyEntry(self)
        
        try:
            entry = Entry.objects.get(
                team=team,
                event=self.event,
                category=category
            )
            print(f"既存エントリー使用: {team.team_name}")
        except Entry.DoesNotExist:
            entry = Entry.objects.create(
                team=team,
                event=self.event,
                category=category,
                owner=team.owner,
                zekken_number=int(team.zekken_number),
                is_active=True,
                hasParticipated=False,
                hasGoaled=False
            )
            print(f"エントリー作成: {team.team_name}")
            self.stats['entries_created'] += 1
        
        return entry
    
    def process_participation(self, entry):
        """イベント参加（2-4）"""
        if self.dry_run:
            print(f"DRY RUN: 参加登録 - {entry.team.team_name}")
            # ダミーメンバーリストを作成
            dummy_members = []
            for i in range(len(entry.team.__dict__.get('dummy_members', []))):
                print(f"  - Member {i+1}")
                self.stats['participations_created'] += 1
            return
        
        # エントリーメンバーを作成
        EntryMember.objects.filter(entry=entry).delete()
        
        for member in entry.team.members.all():
            entry_member = EntryMember.objects.create(
                entry=entry,
                member=member,
                is_temporary=member.is_temporary
            )
            print(f"参加登録: {member.user.firstname}")
            self.stats['participations_created'] += 1
        
        # エントリーを有効化
        entry.is_active = True
        entry.save()
    
    def process_csv_file(self, csv_file_path):
        """CSVファイルを処理"""
        print(f"CSV処理開始: {csv_file_path}")
        
        with open(csv_file_path, 'r', encoding='utf-8') as file:
            # ヘッダーをスキップ
            csv_reader = csv.reader(file)
            header = next(csv_reader)
            print(f"CSVヘッダー: {header[:10]}...")  # 最初の10列を表示
            
            row_count = 0
            for row in csv_reader:
                row_count += 1
                if not any(row):  # 空行をスキップ
                    continue
                
                try:
                    with transaction.atomic():
                        print(f"\n--- Row {row_count}: {row[3] if len(row) > 3 else 'Unknown'} ---")
                        
                        # CSV行をパース
                        data = self.parse_csv_row(row)
                        
                        # カテゴリ取得
                        category = self.get_or_create_category(data['department'], data['hours'])
                        
                        # DRY RUNの場合はトランザクションを無効化
                        if self.dry_run:
                            # DRY RUN処理
                            # 2-1. ユーザー処理
                            main_user = self.process_user(data)
                            
                            # メンバー用ダミーユーザー作成
                            all_users = self.create_dummy_users_for_members(data, main_user)
                            
                            # 2-2. チーム登録
                            team = self.process_team(data, main_user, category)
                            
                            # メンバー登録
                            self.process_members(data, team, all_users)
                            
                            # 2-3. エントリー登録
                            entry = self.process_entry(team, category)
                            
                            # 2-4. イベント参加
                            self.process_participation(entry)
                        else:
                            # 実際の処理
                            # 2-1. ユーザー処理
                            main_user = self.process_user(data)
                            
                            # メンバー用ダミーユーザー作成
                            all_users = self.create_dummy_users_for_members(data, main_user)
                            
                            # 2-2. チーム登録
                            team = self.process_team(data, main_user, category)
                            
                            # メンバー登録
                            self.process_members(data, team, all_users)
                            
                            # 2-3. エントリー登録
                            entry = self.process_entry(team, category)
                            
                            # 2-4. イベント参加
                            self.process_participation(entry)
                        
                        print(f"Row {row_count} 完了: {data['team_name']}")
                        
                except Exception as e:
                    error_msg = f"Row {row_count} エラー: {str(e)}"
                    print(f"エラー: {error_msg}")
                    self.stats['errors'].append(error_msg)
        
        print(f"\nCSV処理完了: {row_count} 行処理")
    
    def print_stats(self):
        """統計情報を表示"""
        print("\n=== 処理結果統計 ===")
        print(f"作成されたユーザー: {self.stats['users_created']}")
        print(f"更新されたユーザー: {self.stats['users_updated']}")
        print(f"作成されたチーム: {self.stats['teams_created']}")
        print(f"作成されたメンバー: {self.stats['members_created']}")
        print(f"作成されたエントリー: {self.stats['entries_created']}")
        print(f"作成された参加登録: {self.stats['participations_created']}")
        print(f"エラー数: {len(self.stats['errors'])}")
        
        if self.stats['errors']:
            print("\n=== エラー詳細 ===")
            for error in self.stats['errors']:
                print(f"- {error}")


def main():
    """メイン処理"""
    parser = argparse.ArgumentParser(description='CSVからチーム情報をデータベースに登録')
    parser.add_argument('--event_code', required=True, help='イベントコード')
    parser.add_argument('--csv_file', 
                       default='CPLIST/input/teams2025.csv',
                       help='CSVファイルパス (デフォルト: CPLIST/input/teams2025.csv)')
    parser.add_argument('--dry_run', action='store_true',
                       help='ドライランモード（実際のDB更新を行わない）')
    
    args = parser.parse_args()
    
    # CSVファイルの存在確認
    if not os.path.exists(args.csv_file):
        print(f"エラー: CSVファイルが見つかりません: {args.csv_file}")
        sys.exit(1)
    
    try:
        # プロセッサーを初期化
        processor = TeamRegistrationProcessor(args.event_code, dry_run=args.dry_run)
        processor.initialize()
        
        # CSVファイルを処理
        processor.process_csv_file(args.csv_file)
        
        # 統計情報を表示
        processor.print_stats()
        
        if args.dry_run:
            print(f"\nDRY RUN 完了: イベント {args.event_code}")
        else:
            print(f"\n処理完了: イベント {args.event_code}")
        
    except Exception as e:
        print(f"処理エラー: {str(e)}")
        sys.exit(1)


if __name__ == '__main__':
    main()
