import 'dart:convert';
import 'dart:ui';

import '../entities/beet.dart';
import '../entities/beet_entry_return.dart';
import '../entities/plant.dart';
import '../entities/plant_time.dart';
import 'api_entities/beet_entry.dart';
import 'http_connection.dart';

class GardenApiService {
  final HttpConnector httpConnector;

  GardenApiService(this.httpConnector);

  Future<List<Plant>> getAllAvailablePlants() async {
    final response = await httpConnector.getAllPlants();

    if (response.statusCode == 200) {
      final List<dynamic> data = json.decode(response.body);

      return data.map<Plant>((plantData) => convertPlant(plantData)).toList();
    } else {
      throw Exception('Failed to fetch plants');
    }
  }

  Future<String> saveBeet(Beet beet) async {
    final beetEntries = _generateBeetEntries(beet);

    final body =
        jsonEncode(beetEntries.map((entry) => entry.toJson()).toList());
    final beetSaved = (await httpConnector.saveBeet(body)).statusCode == 200;

    return beetSaved
        ? 'Beet wurde erfolgreich gespeichert'
        : 'Fehler beim Speichern des Beets.';
  }

  Future<List<BeetApiEntryReturn>> getBeet() async {
    final response = await httpConnector.getBeet();

    if (response.statusCode == 200) {
      final List<dynamic> sortedBeetEntriesFormDB =
          _sortBeetFromDB(response.body);

      final List<BeetApiEntryReturn> beetReturn = [];

      for (final entry in sortedBeetEntriesFormDB) {
        final plant = await getPlant(entry['plant_id'] as int);
        beetReturn.add(BeetApiEntryReturn(plant, entry['beet_row'] as int));
      }

      return beetReturn;
    } else {
      throw Exception('Failed to getBeet from api');
    }
  }

  List<dynamic> _sortBeetFromDB(String response) {
    final List<dynamic> entries = json.decode(response);

    entries.sort((a, b) {
      final int rowA = a['beet_row'] as int;
      final int rowB = b['beet_row'] as int;
      final int positionA = a['position'] as int;
      final int positionB = b['position'] as int;

      if (rowA == rowB) {
        return positionA.compareTo(positionB);
      } else {
        return rowA.compareTo(rowB);
      }
    });

    return entries;
  }

  Future<Plant> getPlant(int id) async {
    final response = await httpConnector.getPlant(id);

    if (response.statusCode == 200) {
      final dynamic data = json.decode(response.body);

      return convertPlant(data);
    } else {
      throw Exception('Failed to fetch plant with id: $id');
    }
  }

  Plant convertPlant(dynamic plantData) {
    final List<dynamic> timesData = plantData['times'];

    final plantTimes = timesData
        .map((time) => PlantTime(
              color: Color(int.parse(time['color'])),
              description: time['description'] as String,
              from: DateTime.parse(time['from_date']),
              until: DateTime.parse(time['until_date']),
              action: time['action_needed'] as bool,
            ))
        .toList();

    final plant = Plant(
      id: plantData['id'] as int,
      name: plantData['name'] as String,
      waterRequirement: plantData['water_requirement'].toDouble(),
      horizontalSpace: plantData['horizontal_space'].toDouble(),
      verticalSpace: plantData['vertical_space'].toDouble(),
      supType: plantData['description'] as String,
      imagePath: plantData['image_path'].toString(),
      times: plantTimes,
    );

    return plant;
  }

  List<BeetEntry> _generateBeetEntries(Beet beet) {
    final entries = <BeetEntry>[];

    for (int row = 0; row < beet.beetRows.length; row++) {
      for (int position = 0;
          position < beet.beetRows[row].plants.length;
          position++) {
        final plantId = beet.beetRows[row].plants[position].id;
        final entry = BeetEntry(plantId, position, row);
        entries.add(entry);
      }
    }

    return entries;
  }
}
