import 'dart:convert';
import 'dart:io';

import 'package:flutter/services.dart';
import 'package:logger/logger.dart';

import '../domain/entities/function_button_config.dart';
import '../domain/entities/server_config.dart';

/// Application configuration loaded from servers.json
class AppConfig {
  final List<ServerConfig> servers;
  final String coordinatorUrl;
  final String keyboardId;
  final FunctionButtonConfig functionButtons;
  final int alarmSyncIntervalSeconds;
  final int connectionRetrySeconds;
  final int commandTimeoutSeconds;

  const AppConfig({
    required this.servers,
    this.coordinatorUrl = 'http://localhost:8090',
    this.keyboardId = 'keyboard-1',
    this.functionButtons = const FunctionButtonConfig(),
    this.alarmSyncIntervalSeconds = 30,
    this.connectionRetrySeconds = 5,
    this.commandTimeoutSeconds = 10,
  });

  /// Load configuration from file or assets
  static Future<AppConfig> load({String? configPath}) async {
    final logger = Logger();
    Map<String, dynamic> configJson;

    // Try loading from file path first
    if (configPath != null) {
      try {
        final file = File(configPath);
        if (await file.exists()) {
          final contents = await file.readAsString();
          configJson = jsonDecode(contents) as Map<String, dynamic>;
          logger.i('Loaded config from: $configPath');
          return _parseConfig(configJson);
        }
      } catch (e) {
        logger.w('Failed to load config from file: $e');
      }
    }

    // Try common file locations
    final commonPaths = [
      'servers.json',
      '../servers.json',
      'config/servers.json',
      r'C:\DEV\COPILOT_D6\servers.json',
    ];

    for (final path in commonPaths) {
      try {
        final file = File(path);
        if (await file.exists()) {
          final contents = await file.readAsString();
          configJson = jsonDecode(contents) as Map<String, dynamic>;
          logger.i('Loaded config from: $path');
          return _parseConfig(configJson);
        }
      } catch (e) {
        // Continue to next path
      }
    }

    // Try loading from assets
    try {
      final contents = await rootBundle.loadString('assets/config/servers.json');
      configJson = jsonDecode(contents) as Map<String, dynamic>;
      logger.i('Loaded config from assets');
      return _parseConfig(configJson);
    } catch (e) {
      logger.w('Failed to load config from assets: $e');
    }

    // Return default empty config
    logger.w('No config file found, using defaults');
    return const AppConfig(servers: []);
  }

  static AppConfig _parseConfig(Map<String, dynamic> json) {
    final serversJson = json['servers'] as List<dynamic>? ?? [];
    final servers = serversJson
        .map((s) => ServerConfig.fromJson(s as Map<String, dynamic>))
        .where((s) => s.enabled)
        .toList();

    final settings = json['settings'] as Map<String, dynamic>? ?? {};

    // Parse function button config
    final fbJson = json['functionButtons'] as Map<String, dynamic>?;
    final functionButtons = fbJson != null
        ? FunctionButtonConfig.fromJson(fbJson)
        : const FunctionButtonConfig();

    return AppConfig(
      servers: servers,
      coordinatorUrl: settings['coordinatorUrl'] as String? ?? 'http://localhost:8090',
      keyboardId: settings['keyboardId'] as String? ?? 'keyboard-1',
      functionButtons: functionButtons,
      alarmSyncIntervalSeconds: settings['alarmSyncIntervalSeconds'] as int? ?? 30,
      connectionRetrySeconds: settings['connectionRetrySeconds'] as int? ?? 5,
      commandTimeoutSeconds: settings['commandTimeoutSeconds'] as int? ?? 10,
    );
  }

  /// Get servers by type
  List<ServerConfig> getServersByType(ServerType type) {
    return servers.where((s) => s.type == type).toList();
  }

  /// Get server that owns a camera ID
  ServerConfig? getServerForCamera(int cameraId) {
    for (final server in servers) {
      if (server.ownsCamera(cameraId)) {
        return server;
      }
    }
    return null;
  }

  /// Get server that owns a monitor ID
  ServerConfig? getServerForMonitor(int monitorId) {
    for (final server in servers) {
      if (server.ownsMonitor(monitorId)) {
        return server;
      }
    }
    return null;
  }

  /// Get total camera count across all servers
  int get totalCameras {
    int count = 0;
    for (final server in servers) {
      count += (server.cameraRangeEnd - server.cameraRangeStart + 1);
    }
    return count;
  }

  /// Get total monitor count across all servers
  int get totalMonitors {
    int count = 0;
    for (final server in servers) {
      count += (server.monitorRangeEnd - server.monitorRangeStart + 1);
    }
    return count;
  }

  /// Get all camera IDs
  List<int> get allCameraIds {
    final ids = <int>[];
    for (final server in servers) {
      for (int i = server.cameraRangeStart; i <= server.cameraRangeEnd; i++) {
        ids.add(i);
      }
    }
    ids.sort();
    return ids;
  }

  /// Get all monitor IDs
  List<int> get allMonitorIds {
    final ids = <int>[];
    for (final server in servers) {
      for (int i = server.monitorRangeStart; i <= server.monitorRangeEnd; i++) {
        ids.add(i);
      }
    }
    ids.sort();
    return ids;
  }
}
