import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../core/config.dart';
import '../providers/auth_provider.dart';
import 'models/match.dart';
import 'models/recording_item.dart';
import 'models/stream_session.dart';
import 'models/team.dart';
import 'models/user.dart';

final apiClientProvider = Provider<ApiClient>((ref) {
  final auth = ref.watch(authProvider);
  return ApiClient(accessToken: auth.accessToken);
});

class ApiClient {
  ApiClient({this.accessToken}) {
    _dio = Dio(
      BaseOptions(
        baseUrl: AppConfig.apiV1,
        connectTimeout: const Duration(seconds: 15),
        receiveTimeout: const Duration(seconds: 15),
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
        },
      ),
    );

    _dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) {
          if (accessToken != null && accessToken!.isNotEmpty) {
            options.headers['Authorization'] = 'Bearer $accessToken';
          }
          handler.next(options);
        },
      ),
    );
  }

  late final Dio _dio;
  final String? accessToken;

  // --- Auth ---

  Future<({User user, AuthTokens tokens})> login({
    required String email,
    required String password,
  }) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/auth/login',
      data: {'email': email, 'password': password},
    );
    final data = response.data!;
    return (
      user: User.fromJson(data['user'] as Map<String, dynamic>),
      tokens: AuthTokens.fromJson(data),
    );
  }

  Future<AuthTokens> refresh(String refreshToken) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/auth/refresh',
      data: {'refresh_token': refreshToken},
    );
    return AuthTokens.fromJson(response.data!);
  }

  Future<User> me() async {
    final response = await _dio.get<Map<String, dynamic>>('/auth/me');
    return User.fromJson(response.data!);
  }

  Future<void> logout() async {
    await _dio.post('/auth/logout');
  }

  // --- Teams ---

  Future<List<Team>> fetchTeams() async {
    final response = await _dio.get<List<dynamic>>('/teams');
    return response.data!
        .map((e) => Team.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  Future<List<RecordingItem>> fetchRecordings(String teamId) async {
    final response = await _dio.get<List<dynamic>>('/teams/$teamId/recordings');
    return response.data!
        .map((e) => RecordingItem.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  // --- Matches ---

  Future<List<MatchModel>> fetchMatches(String teamId) async {
    final response =
        await _dio.get<List<dynamic>>('/teams/$teamId/matches');
    return response.data!
        .map((e) => MatchModel.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  Future<MatchModel> fetchMatch(String matchId) async {
    final response =
        await _dio.get<Map<String, dynamic>>('/matches/$matchId');
    return MatchModel.fromJson(response.data!);
  }

  Future<MatchModel> updateMatch(String matchId, Map<String, dynamic> body) async {
    final response = await _dio.patch<Map<String, dynamic>>(
      '/matches/$matchId',
      data: {'match': body},
    );
    return MatchModel.fromJson(response.data!);
  }

  Future<void> deleteMatch(String matchId) async {
    await _dio.delete<void>('/matches/$matchId');
  }

  Future<MatchModel> createMatch(String teamId, Map<String, dynamic> body) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/teams/$teamId/matches',
      data: {'match': body},
    );
    return MatchModel.fromJson(response.data!);
  }

  // --- Sessions ---

  Future<StreamSession> createSession(
    String matchId, {
    String platform = 'matchlivetv',
    String privacyStatus = 'unlisted',
    String qualityPreset = '720p_30_2.5mbps',
    int? targetBitrate,
    int? targetFps,
  }) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/matches/$matchId/sessions',
      data: {
        'platform': platform,
        'privacy_status': privacyStatus,
        'quality_preset': qualityPreset,
        if (targetBitrate != null) 'target_bitrate': targetBitrate,
        if (targetFps != null) 'target_fps': targetFps,
      },
    );
    return StreamSession.fromJson(response.data!);
  }

  Future<StreamSession> fetchSession(String sessionId) async {
    final response =
        await _dio.get<Map<String, dynamic>>('/sessions/$sessionId');
    return StreamSession.fromJson(response.data!);
  }

  Future<StreamSession> startSession(String sessionId) async {
    final response =
        await _dio.patch<Map<String, dynamic>>('/sessions/$sessionId/start');
    return StreamSession.fromJson(response.data!);
  }

  Future<StreamSession> stopSession(String sessionId) async {
    final response =
        await _dio.patch<Map<String, dynamic>>('/sessions/$sessionId/stop');
    return StreamSession.fromJson(response.data!);
  }

  Future<StreamSession> pauseSession(String sessionId) async {
    final response =
        await _dio.patch<Map<String, dynamic>>('/sessions/$sessionId/pause');
    return StreamSession.fromJson(response.data!);
  }

  Future<RegiaLinkResponse> createRegiaLink(String sessionId) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/sessions/$sessionId/regia_link',
    );
    return RegiaLinkResponse.fromJson(response.data!);
  }

  Future<PairingTokenResponse> createPairingToken(String sessionId) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/sessions/$sessionId/pairing_token',
    );
    return PairingTokenResponse.fromJson(response.data!);
  }

  Future<StreamSession> claimPairing({
    required String sessionId,
    required String pairingToken,
    required String deviceRole,
  }) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/sessions/$sessionId/claim_pairing',
      data: {
        'pairing_token': pairingToken,
        'device_role': deviceRole,
      },
    );
    return StreamSession.fromJson(response.data!);
  }

  Future<NetworkTestResult> networkTest({
    required String sessionId,
    required double downloadMbps,
    required double uploadMbps,
    required int latencyMs,
    required String networkType,
  }) async {
    final response = await _dio.post<Map<String, dynamic>>(
      '/sessions/$sessionId/network_test',
      data: {
        'download_mbps': downloadMbps,
        'upload_mbps': uploadMbps,
        'latency_ms': latencyMs,
        'network_type': networkType,
      },
    );
    return NetworkTestResult.fromJson(response.data!);
  }

  Future<YoutubeStats> youtubeStats(String sessionId) async {
    final response =
        await _dio.get<Map<String, dynamic>>('/sessions/$sessionId/youtube_stats');
    return YoutubeStats.fromJson(response.data!);
  }

  Future<void> postTelemetry({
    required String sessionId,
    required String deviceRole,
    int? batteryLevel,
    String? networkType,
    int? signalStrength,
    int? currentBitrate,
    int? targetBitrate,
    int? fps,
  }) async {
    await _dio.post(
      '/sessions/$sessionId/telemetry',
      data: {
        'device_role': deviceRole,
        if (batteryLevel != null) 'battery_level': batteryLevel,
        if (networkType != null) 'network_type': networkType,
        if (signalStrength != null) 'signal_strength': signalStrength,
        if (currentBitrate != null) 'current_bitrate': currentBitrate,
        if (targetBitrate != null) 'target_bitrate': targetBitrate,
        if (fps != null) 'fps': fps,
      },
    );
  }
}
