import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../config/api_config.dart';
import '../models/event_model.dart';
import '../models/participant_model.dart';
import '../models/score_model.dart';
import '../models/team_model.dart';
import './api_service.dart';

class EventService with ChangeNotifier {
  List<Event> _events = [];
  Event? _currentEvent;
  List<Participant> _participants = [];
  List<Score> _scores = [];
  List<Team> _teams = [];
  bool _isLoading = false;
  String? _token;
  final ApiService _apiService;
  String? _clubId;

  // 기본 생성자
  EventService() : _apiService = ApiService();

  // 테스트용 생성자
  EventService.forTest(this._apiService);

  List<Event> get events => [..._events];
  Event? get currentEvent => _currentEvent;
  List<Participant> get participants => [..._participants];
  List<Score> get scores => [..._scores];
  List<Team> get teams => [..._teams];
  bool get isLoading => _isLoading;

  // 초기화 함수
  Future<void> initialize(String token) async {
    _token = token;
    _apiService.setToken(token);
  }

  // 클럽 ID 설정
  void setClubId(String clubId) {
    _clubId = clubId;
    notifyListeners();
  }

  // 클럽의 모든 이벤트 가져오기
  Future<void> fetchClubEvents() async {
    print('fetchClubEvents 호출됨: token=$_token');

    _isLoading = true;
    notifyListeners();

    try {
      // 클럽 ID 가져오기
      final prefs = await SharedPreferences.getInstance();
      final clubId = prefs.getString(ApiConfig.clubIdKey);

      if (clubId == null) {
        throw Exception('선택된 클럽이 없습니다');
      }

      final data = await _apiService.post(
        '${ApiConfig.clubs}/events',
        data: {'clubId': clubId},
      );

      // 응답 데이터가 리스트 형태로 직접 왔는지 확인
      if (data is List) {
        final List<dynamic> eventsData = data;
        _events = eventsData
            .map((eventData) => Event.fromJson(eventData))
            .toList();
      } else {
        // 응답 데이터가 객체 형태로 왔을 경우 events 키를 통해 접근
        final List<dynamic> eventsData = data['events'] ?? [];
        _events = eventsData
            .map((eventData) => Event.fromJson(eventData))
            .toList();
      }

      _isLoading = false;
      notifyListeners();
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('이벤트 목록을 불러오는데 실패했습니다: $e');
    }
  }

  // ID로 이벤트 정보 가져오기
  Future<Event> fetchEventById(String eventId) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    try {
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events/detail',
        data: {'eventId': eventId},
      );

      return Event.fromJson(data['event']);
    } catch (e) {
      throw Exception('이벤트 정보를 불러오는데 실패했습니다: $e');
    }
  }

  // 이벤트 생성
  Future<Event> createEvent(Map<String, dynamic> eventData) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events',
        data: eventData,
      );

      final newEvent = Event.fromJson(data['event']);

      _events.add(newEvent);

      _isLoading = false;
      notifyListeners();

      return newEvent;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('이벤트 생성에 실패했습니다: $e');
    }
  }

  // 이벤트 정보 업데이트
  Future<Event> updateEvent(
    String eventId,
    Map<String, dynamic> updates,
  ) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final data = await _apiService.put(
        '${ApiConfig.clubs}/events/$eventId',
        data: updates,
      );

      final updatedEvent = Event.fromJson(data['event']);

      // 이벤트 목록 업데이트
      final index = _events.indexWhere((event) => event.id == eventId);
      if (index >= 0) {
        _events[index] = updatedEvent;
      }

      _isLoading = false;
      notifyListeners();

      return updatedEvent;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('이벤트 정보 업데이트에 실패했습니다: $e');
    }
  }

  // 이벤트 삭제
  Future<bool> deleteEvent(String eventId) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      await _apiService.delete('${ApiConfig.clubs}/events/$eventId');

      // 이벤트 목록에서 삭제
      _events.removeWhere((event) => event.id == eventId);

      _isLoading = false;
      notifyListeners();

      return true;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('이벤트 삭제에 실패했습니다: $e');
    }
  }

  // 참가자 관리 기능
  // 이벤트 참가자 목록 가져오기
  Future<List<Participant>> fetchEventParticipants(String eventId) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      // userId는 일부 라우트에서 필수이므로 prefs에서 읽어 포함
      final prefs = await SharedPreferences.getInstance();
      final userId = prefs.getString(ApiConfig.userIdKey);
      final payload = {
        'clubId': _clubId,
        if (userId != null) 'userId': userId,
        'eventId': eventId,
      };
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events/$eventId/participants/list',
        data: payload,
      );

      // 응답이 리스트이거나 객체 내 participants 키로 올 수 있어 모두 처리
      final List<dynamic> participantsData = (data is List)
          ? data
          : (data['participants'] ?? []);
      _participants = participantsData
          .map((participantData) => Participant.fromJson(participantData))
          .toList();

      _isLoading = false;
      notifyListeners();

      return _participants;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('참가자 목록을 불러오는데 실패했습니다: $e');
    }
  }

  // 참가자 추가
  Future<Participant> addParticipant(
    String eventId,
    Map<String, dynamic> participantData,
  ) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      // 참가자 페이로드 정규화: 상태/결제 상태 표준화 및 빈 문자열 null 처리
      final normalized = _sanitizeParticipantPayload(participantData);
      final payload = {'clubId': _clubId, ...normalized};
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events/$eventId/participants',
        data: payload,
      );

      final newParticipant = Participant.fromJson(data['participant']);

      _participants.add(newParticipant);

      _isLoading = false;
      notifyListeners();

      return newParticipant;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('참가자 추가에 실패했습니다: $e');
    }
  }

  // 참가자 정보 업데이트
  Future<Participant> updateParticipant(
    String eventId,
    String participantId,
    Map<String, dynamic> updates,
  ) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      // 업데이트 페이로드도 동일한 규칙으로 정규화
      final normalized = _sanitizeParticipantPayload(updates);
      final data = await _apiService.put(
        '${ApiConfig.clubs}/events/$eventId/participants/$participantId',
        data: normalized,
      );

      final updatedParticipant = Participant.fromJson(data['participant']);

      // 참가자 목록 업데이트
      final index = _participants.indexWhere(
        (participant) => participant.id == participantId,
      );
      if (index >= 0) {
        _participants[index] = updatedParticipant;
      }

      _isLoading = false;
      notifyListeners();

      return updatedParticipant;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('참가자 정보 업데이트에 실패했습니다: $e');
    }
  }

  // 참가자 페이로드 정규화 헬퍼
  Map<String, dynamic> _sanitizeParticipantPayload(Map<String, dynamic> data) {
    final Map<String, dynamic> out = Map<String, dynamic>.from(data);

    // 상태 표준화: 구버전/철자 변형 호환
    final statusRaw = (out['status']?.toString().trim() ?? '').toLowerCase();
    if (statusRaw.isNotEmpty) {
      String status = statusRaw;
      if (status == 'cancelled') status = 'canceled';
      // 허용 목록: registered, pending, confirmed, canceled
      if (![
        'registered',
        'pending',
        'confirmed',
        'canceled',
      ].contains(status)) {
        // 허용 외 값은 안전하게 pending 처리
        status = 'pending';
      }
      out['status'] = status;
    }

    // 결제 상태 표준화: isPaid -> paymentStatus 변환 및 강제
    if (out.containsKey('isPaid') &&
        (out['paymentStatus'] == null ||
            (out['paymentStatus'].toString().isEmpty))) {
      final isPaidVal = out['isPaid'] == true;
      out['paymentStatus'] = isPaidVal ? 'paid' : 'unpaid';
    }
    final payRaw = (out['paymentStatus']?.toString().trim() ?? '')
        .toLowerCase();
    if (payRaw.isNotEmpty) {
      out['paymentStatus'] = (payRaw == 'paid') ? 'paid' : 'unpaid';
    }
    // 서버 스키마에 맞추기 위해 isPaid 키는 제거 (서버는 paymentStatus만 사용)
    out.remove('isPaid');

    // 빈 문자열을 명시적 null로 변환 (이름/이메일/전화/메모 등)
    out.updateAll((key, value) {
      if (value is String && value.trim().isEmpty) return null;
      return value;
    });

    return out;
  }

  // 참가자 삭제
  Future<bool> removeParticipant(String eventId, String participantId) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      await _apiService.delete(
        '${ApiConfig.clubs}/events/$eventId/participants/$participantId',
      );

      // 참가자 목록에서 삭제
      _participants.removeWhere(
        (participant) => participant.id == participantId,
      );

      _isLoading = false;
      notifyListeners();

      return true;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('참가자 삭제에 실패했습니다: $e');
    }
  }

  // 참가자 상태 업데이트
  Future<Participant> updateParticipantStatus(
    String eventId,
    String participantId,
    String status,
  ) async {
    return updateParticipant(eventId, participantId, {'status': status});
  }

  // 점수 관리 기능
  // 이벤트 점수 목록 가져오기
  Future<List<Score>> fetchEventScores(String eventId) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events/scores',
        data: {'eventId': eventId},
      );

      final List<dynamic> scoresData = data['scores'] ?? [];
      _scores = scoresData
          .map((scoreData) => Score.fromJson(scoreData))
          .toList();

      _isLoading = false;
      notifyListeners();

      return _scores;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('점수 목록을 불러오는데 실패했습니다: $e');
    }
  }

  // 점수 추가
  Future<Score> addScore(String eventId, Map<String, dynamic> scoreData) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events/$eventId/scores',
        data: scoreData,
      );

      final newScore = Score.fromJson(data['score']);

      _scores.add(newScore);

      _isLoading = false;
      notifyListeners();

      return newScore;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('점수 추가에 실패했습니다: $e');
    }
  }

  // 점수 업데이트
  Future<Score> updateScore(
    String eventId,
    String scoreId,
    Map<String, dynamic> updates,
  ) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final data = await _apiService.put(
        '${ApiConfig.clubs}/events/$eventId/scores/$scoreId',
        data: updates,
      );

      final updatedScore = Score.fromJson(data['score']);

      // 점수 목록 업데이트
      final index = _scores.indexWhere((score) => score.id == scoreId);
      if (index >= 0) {
        _scores[index] = updatedScore;
      }

      _isLoading = false;
      notifyListeners();

      return updatedScore;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('점수 업데이트에 실패했습니다: $e');
    }
  }

  // 점수 삭제
  Future<bool> deleteScore(String eventId, String scoreId) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      await _apiService.delete(
        '${ApiConfig.clubs}/events/$eventId/scores/$scoreId',
      );

      // 점수 목록에서 삭제
      _scores.removeWhere((score) => score.id == scoreId);

      _isLoading = false;
      notifyListeners();

      return true;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('점수 삭제에 실패했습니다: $e');
    }
  }

  // 팀 관리 기능
  // 이벤트 팀 목록 가져오기
  Future<List<Team>> fetchEventTeams(String eventId) async {
    if (_token == null) {
      throw Exception('인증 정보가 필요합니다');
    }

    try {
      final data = await _apiService.post(
        '${ApiConfig.events}/teams',
        data: {'eventId': eventId},
      );

      final List<dynamic> teamsData = data['teams'] ?? [];
      _teams = teamsData.map((teamData) => Team.fromJson(teamData)).toList();

      notifyListeners();
      return _teams;
    } catch (e) {
      throw Exception('팀 목록을 불러오는데 실패했습니다: $e');
    }
  }

  // 이벤트에 팀이 있는지 확인 (간략 조회)
  Future<bool> hasEventTeams(String eventId) async {
    if (_token == null) {
      throw Exception('인증 정보가 필요합니다');
    }

    try {
      final data = await _apiService.post(
        '${ApiConfig.events}/teams',
        data: {'eventId': eventId},
      );

      final List<dynamic> teamsData = data['teams'] ?? [];
      return teamsData.isNotEmpty;
    } catch (e) {
      print('팀 확인 실패: $e');
      return false;
    }
  }

  // 팀 생성
  Future<List<Team>> generateTeams(
    String eventId,
    Map<String, dynamic> teamConfig,
  ) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events/$eventId/teams/generate',
        data: teamConfig,
      );

      final List<dynamic> teamsData = data['teams'] ?? [];
      _teams = teamsData.map((teamData) => Team.fromJson(teamData)).toList();

      _isLoading = false;
      notifyListeners();

      return _teams;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('팀 생성에 실패했습니다: $e');
    }
  }

  // 팀 저장
  Future<bool> saveTeams(String eventId, List<Team> teams) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      await _apiService.post(
        '${ApiConfig.clubs}/events/$eventId/teams/save',
        data: {'teams': teams.map((team) => team.toJson()).toList()},
      );

      _teams = teams;

      _isLoading = false;
      notifyListeners();

      return true;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('팀 저장에 실패했습니다: $e');
    }
  }

  // 파일에서 이벤트 일괄 생성
  Future<List<Event>> createEventsFromFile(
    List<Map<String, dynamic>> eventsData,
  ) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      final List<Event> createdEvents = [];

      // 각 이벤트 데이터에 클럽 ID 추가
      for (var eventData in eventsData) {
        eventData['clubId'] = _clubId;

        // null 값 처리 - 빈 문자열을 명시적 null로 변환
        eventData.forEach((key, value) {
          if (value is String && value.isEmpty) {
            eventData[key] = null;
          }
        });

        // 이벤트 생성 API 호출
        final data = await _apiService.post(
          '${ApiConfig.clubs}/events',
          data: eventData,
        );

        final newEvent = Event.fromJson(data['event']);
        createdEvents.add(newEvent);
        _events.add(newEvent);
      }

      _isLoading = false;
      notifyListeners();

      return createdEvents;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('파일에서 이벤트 생성에 실패했습니다: $e');
    }
  }

  // 이벤트 복제
  Future<Event> cloneEvent(String eventId, {String? newName}) async {
    if (_token == null || _clubId == null) {
      throw Exception('인증 또는 클럽 정보가 필요합니다');
    }

    _isLoading = true;
    notifyListeners();

    try {
      // 원본 이벤트 정보 가져오기
      final originalEvent = await fetchEventById(eventId);

      // 복제할 이벤트 데이터 준비
      final Map<String, dynamic> cloneData = {
        'clubId': _clubId,
        'title': newName ?? '${originalEvent.title} (복사본)',
        'description': originalEvent.description,
        'location': originalEvent.location,
        'type': originalEvent.type,
        'status': 'draft', // 복제된 이벤트는 초안 상태로 시작
        'startDate': originalEvent.startDate.toIso8601String(),
        'endDate': originalEvent.endDate?.toIso8601String(),
        'maxParticipants': originalEvent.maxParticipants,
        'participantFee': originalEvent.participantFee,
        'gameCount': originalEvent.gameCount,
        'publicHash': originalEvent.publicHash,
        'accessPassword': originalEvent.accessPassword,
        'isActive': true,
      };

      // 이벤트 생성 API 호출
      final data = await _apiService.post(
        '${ApiConfig.clubs}/events',
        data: cloneData,
      );

      final newEvent = Event.fromJson(data['event']);
      _events.add(newEvent);

      _isLoading = false;
      notifyListeners();

      return newEvent;
    } catch (e) {
      _isLoading = false;
      notifyListeners();
      throw Exception('이벤트 복제에 실패했습니다: $e');
    }
  }
}
