import 'package:dartz/dartz.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:tugas_akhir_supabase/core/errors/exceptions.dart';
import 'package:tugas_akhir_supabase/core/errors/failures.dart';
import 'package:tugas_akhir_supabase/data/models/crop_schedule_model.dart';
import 'package:tugas_akhir_supabase/domain/entities/crop_schedule.dart';
import 'package:tugas_akhir_supabase/domain/repositories/crop_schedule_repository.dart';

class CropScheduleRepositoryImpl implements CropScheduleRepository {
  final SupabaseClient supabaseClient;

  CropScheduleRepositoryImpl({required this.supabaseClient});

  @override
  Future<Either<Failure, List<CropSchedule>>> getSchedules(
    String userId,
  ) async {
    try {
      final response = await supabaseClient
          .from('crop_schedules')
          .select()
          .eq('user_id', userId);

      final schedules =
          (response as List).map((e) => CropScheduleModel.fromJson(e)).toList();

      return Right(schedules);
    } on PostgrestException catch (e) {
      return Left(DatabaseFailure(message: e.message));
    } catch (e) {
      return Left(ServerFailure(message: e.toString()));
    }
  }

  @override
  Future<Either<Failure, CropSchedule>> createSchedule(
    String userId,
    CropSchedule schedule,
  ) async {
    try {
      final scheduleModel = CropScheduleModel.fromEntity(schedule);
      final data = scheduleModel.toJson();
      data['user_id'] = userId;

      final response =
          await supabaseClient
              .from('crop_schedules')
              .insert(data)
              .select()
              .single();

      return Right(CropScheduleModel.fromJson(response));
    } on PostgrestException catch (e) {
      return Left(DatabaseFailure(message: e.message));
    } catch (e) {
      return Left(ServerFailure(message: e.toString()));
    }
  }

  @override
  Future<Either<Failure, CropSchedule>> updateSchedule(
    String userId,
    CropSchedule schedule,
  ) async {
    try {
      final scheduleModel = CropScheduleModel.fromEntity(schedule);
      final data = scheduleModel.toJson();

      final response =
          await supabaseClient
              .from('crop_schedules')
              .update(data)
              .eq('id', schedule.id)
              .eq('user_id', userId)
              .select()
              .single();

      return Right(CropScheduleModel.fromJson(response));
    } on PostgrestException catch (e) {
      return Left(DatabaseFailure(message: e.message));
    } catch (e) {
      return Left(ServerFailure(message: e.toString()));
    }
  }

  @override
  Future<Either<Failure, bool>> deleteSchedule(
    String userId,
    String scheduleId,
  ) async {
    try {
      await supabaseClient
          .from('crop_schedules')
          .delete()
          .eq('id', scheduleId)
          .eq('user_id', userId);

      return const Right(true);
    } on PostgrestException catch (e) {
      return Left(DatabaseFailure(message: e.message));
    } catch (e) {
      return Left(ServerFailure(message: e.toString()));
    }
  }

  @override
  Future<Either<Failure, Map<String, dynamic>?>> getActiveSchedule(
    String userId,
  ) async {
    try {
      final now = DateTime.now();

      final response =
          await supabaseClient
              .from('crop_schedules')
              .select('id, crop_name')
              .eq('user_id', userId)
              .lte('start_date', now.toIso8601String())
              .gte('end_date', now.toIso8601String())
              .order('created_at', ascending: false)
              .limit(1)
              .maybeSingle();

      if (response == null) {
        return const Right(null);
      }

      return Right({
        'scheduleId': response['id'],
        'cropName': response['crop_name'],
      });
    } on PostgrestException catch (e) {
      return Left(DatabaseFailure(message: e.message));
    } catch (e) {
      return Left(ServerFailure(message: e.toString()));
    }
  }
}
