import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:niogu_app/core/database/app_database.dart';
import 'package:niogu_app/core/models/outlet_model.dart';
import 'package:niogu_app/core/providers/app_provider.dart';
import 'package:niogu_app/core/database/database_holder.dart';
import 'package:niogu_app/core/utils/image_service.dart';
import 'package:niogu_app/core/system/system_secure.dart';
import 'package:niogu_app/core/system/system_setting.dart';
import 'package:niogu_app/core/enums/user_role.dart';
import 'package:niogu_app/features/auth/domain/entities/user.dart';
import 'package:niogu_app/features/auth/domain/repositories/i_auth_repository.dart';
import 'package:niogu_app/features/auth/presentation/providers/auth_provider.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

class AuthController extends AutoDisposeAsyncNotifier<void> {
  late final IAuthRepository _repository;

  late final Dio _dio;

  @override
  FutureOr<void> build() {
    _repository = ref.read(authRepositoryProvider);

    _dio = ref.read(dioProvider);
  }

  Future<String?> _handleBusinessLogo(String? serverLogoUrl) async {
    try {
      if (serverLogoUrl != null && serverLogoUrl.isNotEmpty) {
        final tempDir = await getTemporaryDirectory();
        final tempPath = p.join(tempDir.path, 'temp_logo.jpg');

        await _dio.download(serverLogoUrl, tempPath);

        return await ImageService.saveImageToLocalDirectory(
          File(tempPath),
          'logo_images',
        );
      }

      return null;
    } catch (e) {
      rethrow;
    }
  }

  Future<Map<String, String?>> _handleOutletBanners(
    List<OutletModel> outletModels,
  ) async {
    try {
      final Map<String, String?> localBannerPaths = {};

      for (final outlet in outletModels) {
        final id = outlet.serverId;

        final banner = outlet.serverBannerUrl;

        if (banner != null && banner.isNotEmpty) {
          final tempDir = await getTemporaryDirectory();
          final tempPath = p.join(tempDir.path, 'temp_logo.jpg');

          await _dio.download(banner, tempPath);

          final localBannerPath = await ImageService.saveImageToLocalDirectory(
            File(tempPath),
            'outlet_banner_images',
          );

          localBannerPaths.putIfAbsent(id, () => localBannerPath);
        }
      }

      return localBannerPaths;
    } catch (e) {
      rethrow;
    }
  }

  Future<void> login(LoginUser user) async {
    state = const AsyncValue.loading();

    final result = await AsyncValue.guard(() async {
      final response = await _repository.login(user);

      final data = response.data!;

      final tenantModel = data.user.tenant;

      final outletModels = data.user.outlets;

      final userModel = data.user;

      final staffModels = userModel.staffs;

      final localLogoPath = await _handleBusinessLogo(
        tenantModel.serverLogoUrl,
      );

      final localBannerPaths = await _handleOutletBanners(outletModels);

      final accessToken = data.accessToken;

      await clearDatabase();

      await SystemSetting.setTenant(
        tenantId: tenantModel.serverId,
        tenantCode: tenantModel.businessCode,
        tenantName: tenantModel.businessName,
      );

      await Future.delayed(Duration.zero);

      final appDatabase = AppDatabase();

      await setDatabase(appDatabase);

      await appDatabase.customSelect("SELECT 1").getSingle();

      await appDatabase.userDao.login(
        tenantModel: tenantModel,
        outletModels: outletModels,
        userModel: userModel,
        staffModels: staffModels,
        localLogoPath: localLogoPath,
        localBannerPaths: localBannerPaths,
        password: user.password,
      );

      ref.invalidate(appDatabaseProvider);

      final syncService = ref.read(syncServiceProvider);

      syncService.stopWatching();

      await syncService.startWatching();

      await SystemSecure.saveAccessToken(accessToken);

      await SystemSetting.setIsLoggedIn();

      String? outletIdByOwner;

      final currentUserRole = UserRole.values.byName(userModel.role);

      if (currentUserRole == UserRole.owner) {
        outletIdByOwner = userModel.outletId;
      }

      await SystemSetting.setOutletIdByOwner(outletIdByOwner);

      final outletName = outletModels
          .firstWhere((outlet) => outlet.serverId == userModel.outletId)
          .name;

      await SystemSetting.switchOutlet(
        outletId: userModel.outletId,
        outletName: outletName,
      );

      await SystemSetting.setUser(
        userId: userModel.serverId,
        userName: userModel.name,
        userEmail: userModel.email,
        userRole: currentUserRole,
      );
    });

    state = result;

    if (result is AsyncError) throw result.error!;
  }

  Future<void> register(RegisterUser register) async {
    state = const AsyncValue.loading();

    final result = await AsyncValue.guard(() async {
      await _repository.register(register);
    });

    state = result;

    if (result is AsyncError) throw result.error!;
  }
}
