import 'package:dio/dio.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import '../../../../core/errors/errors.dart';
import '../../domain/repositories/settings_repository.dart';
import 'settings_event.dart';
import 'settings_state.dart';

class SettingsBloc extends Bloc<SettingsEvent, SettingsState> {
  final SettingsRepository _repository;

  SettingsBloc(this._repository) : super(const SettingsState.initial()) {
    on<SettingsStarted>(_onStarted);
    on<SettingsConfigRequested>(_onConfigRequested);
    on<SettingsApiUrlChanged>(_onApiUrlChanged);
    on<SettingsApiUrlSaved>(_onApiUrlSaved);
    on<SettingsLanguageChanged>(_onLanguageChanged);
    on<SettingsRefreshConfig>(_onRefreshConfig);
  }

  Future<void> _onStarted(SettingsStarted event, emit) async {
    emit(const SettingsState.loading());

    final apiUrl = await _repository.getApiUrl() ?? '';
    final languageCode = await _repository.getLanguageCode() ?? 'ru';

    if (apiUrl.isEmpty) {
      emit(SettingsState.loaded(
        apiUrl: '',
        serverConfig: null,
        languageCode: languageCode,
      ));
      return;
    }
    
    final configResult = await _repository.getServerConfig();
    
    if (configResult.isSuccess) {
      emit(SettingsState.loaded(
        apiUrl: apiUrl,
        serverConfig: configResult.data,
        languageCode: languageCode,
        connectionStatus: ConnectionStatus.connected,
      ));
    } else {
      emit(SettingsState.loaded(
        apiUrl: apiUrl,
        serverConfig: null,
        languageCode: languageCode,
        connectionStatus: ConnectionStatus.error,
        error: _errorMessage(configResult.error!),
      ));
    }
  }

  Future<void> _onConfigRequested(SettingsConfigRequested event, emit) async {
    if (state is! SettingsLoaded) return;
    final currentState = state as SettingsLoaded;

    if (currentState.apiUrl.isEmpty) return;

    emit(currentState.copyWith(connectionStatus: ConnectionStatus.checking));
    final configResult = await _repository.refreshServerConfig();

    if (configResult.isSuccess) {
      emit(SettingsState.loaded(
        apiUrl: currentState.apiUrl,
        serverConfig: configResult.data,
        languageCode: currentState.languageCode,
        connectionStatus: ConnectionStatus.connected,
      ));
    } else {
      emit(SettingsState.loaded(
        apiUrl: currentState.apiUrl,
        serverConfig: null,
        languageCode: currentState.languageCode,
        connectionStatus: ConnectionStatus.error,
        error: _errorMessage(configResult.error!),
      ));
    }
  }

  void _onApiUrlChanged(SettingsApiUrlChanged event, emit) {
    if (state is! SettingsLoaded) return;
    final currentState = state as SettingsLoaded;
    emit(SettingsState.loaded(
      apiUrl: event.url,
      serverConfig: currentState.serverConfig,
      languageCode: currentState.languageCode,
      connectionStatus: ConnectionStatus.unknown,
    ));
  }

  Future<void> _onApiUrlSaved(SettingsApiUrlSaved event, emit) async {
    if (state is! SettingsLoaded) return;
    final currentState = state as SettingsLoaded;
    
    // Нормализуем URL: убираем дублирование /api и другие проблемные суффиксы
    final normalizedUrl = _normalizeApiUrl(event.url);
    
    await _repository.saveApiUrl(normalizedUrl);

    // Обновляем baseUrl у Dio, чтобы последующие запросы шли на новый адрес
    final dio = GetIt.instance<Dio>();
    dio.options.baseUrl = normalizedUrl;

    if (event.url.isEmpty) {
      emit(SettingsState.loaded(
        apiUrl: '',
        serverConfig: null,
        languageCode: currentState.languageCode,
        connectionStatus: ConnectionStatus.unknown,
      ));
      return;
    }

    // Проверяем подключение к новому адресу
    emit(SettingsState.loaded(
      apiUrl: event.url,
      serverConfig: currentState.serverConfig,
      languageCode: currentState.languageCode,
      connectionStatus: ConnectionStatus.checking,
    ));

    final configResult = await _repository.refreshServerConfig();

    if (configResult.isSuccess) {
      emit(SettingsState.loaded(
        apiUrl: event.url,
        serverConfig: configResult.data,
        languageCode: currentState.languageCode,
        connectionStatus: ConnectionStatus.connected,
      ));
    } else {
      emit(SettingsState.loaded(
        apiUrl: event.url,
        serverConfig: null,
        languageCode: currentState.languageCode,
        connectionStatus: ConnectionStatus.error,
        error: _errorMessage(configResult.error!),
      ));
    }
  }

  Future<void> _onLanguageChanged(SettingsLanguageChanged event, emit) async {
    if (state is! SettingsLoaded) return;
    final currentState = state as SettingsLoaded;

    await _repository.saveLanguageCode(event.code);

    emit(SettingsState.loaded(
      apiUrl: currentState.apiUrl,
      serverConfig: currentState.serverConfig,
      languageCode: event.code,
      connectionStatus: currentState.connectionStatus,
    ));
  }

  Future<void> _onRefreshConfig(SettingsRefreshConfig event, emit) async {
    add(const SettingsConfigRequested());
    await Future.delayed(const Duration(milliseconds: 100));
  }

  String _errorMessage(AppError error) => error.when(
    unknown: (msg) => msg?.contains('parsing') == true ? 'parsingError' : 'unknownError',
    network: (msg) => 'networkError',
    unauthorized: (msg) => 'unauthorized',
    forbidden: (msg) => 'forbidden',
    notFound: (msg) => 'notFound',
    server: (code, msg) => 'serverError',
    database: (msg) => 'databaseError',
    validation: (message, errors) => 'validationError',
    parsing: (msg) => 'parsingError',
  );

  String _normalizeApiUrl(String url) {
    if (url.isEmpty) return url;
    
    // Убираем все слэши в конце
    String normalized = url.replaceAll(RegExp(r'/+$'), '');
    
    // Если URL заканчивается на /api, убираем этот суффикс
    // (так как мы всегда добавляем /api к путям при запросе)
    if (normalized.endsWith('/api')) {
      normalized = normalized.substring(0, normalized.length - 4);
      normalized = normalized.replaceAll(RegExp(r'/+$'), '');
    }
    
    return normalized;
  }
}

