import 'dart:convert';

import 'package:ambito/main.dart';
import 'package:ambito/src/entity/area/area_repository.dart';
import 'package:ambito/src/entity/entities.dart';
import 'package:ambito/src/entity/login/login_repository.dart';
import 'package:ambito/src/entity/measure/details/measure_details.dart';
import 'package:ambito/src/entity/measure/details/measure_details_repository.dart';
import 'package:ambito/src/entity/measure/general/measure_general_repository.dart';
import 'package:ambito/src/entity/measure/types_details/measure_types_details.dart';
import 'package:ambito/src/entity/measure/types_details/measure_types_details_repository.dart';
import 'package:ambito/src/packages/ambito_api/restclient.dart';
import 'package:get/get.dart';

import '../../config/config.dart';
import '../../consts/consts.dart';
import '../../entity/area/area.dart';
import '../../entity/business/business_repository.dart';
import '../../entity/funding_program/funding_program_repository.dart';
import '../../entity/login/login.dart';
import '../../entity/measure/measure_repository.dart';

class BaseApi {
  Map tables = {};

  init() {
    // read table ids from .env file...
    tables = baserowIds;
  }

  _getMap() {
    return {
      'area': AreaRepository().put,
      'business': BusinessRepository().put,
      'funding_program': FundingProgramRepository().put,
      'login': LoginRepository().put,
      'measure_types': MeasureRepository().put,
      'measure_general': MeasureGeneralRepository().put,
      'measure_details': MeasureDetailsRepository().put,
      'measure_types_details': MeasureTypesDetailsRepository().put,
    };
  }

  Future<dynamic> patchContent(String table, int id, dynamic body,
      [bool autosave = true]) async {
    init();
    int tableId = tables[table] ?? 0;

    if (tableId <= 0) return false;

    logger.d(body);

    var response = await RestClient().patch('$tableId/$id/', body);
    if (response.statusCode != 200) {
      logger.e(response.headers);
      logger.e(response.body);
      Get.toNamed('/error');
    }

    if (autosave == true) {
      final repositoryMap = _getMap();
      var model = _createModelFromJson(table, jsonDecode(response.body));
      var repositoryFunction = repositoryMap[table];
      if (repositoryFunction == null) return false;
      repositoryFunction(model);
    }

    return response.body;
  }

  Future<bool> deleteContent(String table, int id) async {
    init();
    int tableId = tables[table] ?? 0;

    if (tableId <= 0) return false;

    var response = await RestClient().delete('$tableId/$id/');
    if (response.statusCode != 200) Get.toNamed('/error');
    return true;
  }

  Future<dynamic> postContent(String table, dynamic body,
      [bool autosave = true]) async {
    init();
    int tableId = tables[table] ?? 0;

    if (tableId <= 0) return false;

    final repositoryMap = _getMap();

    var response = await RestClient().post('$tableId/', body);
    if (response.statusCode != 200) Get.toNamed('/error');

    if (autosave == true) {
      var model = _createModelFromJson(table, jsonDecode(response.body));
      var repositoryFunction = repositoryMap[table];
      if (repositoryFunction == null) return false;
      repositoryFunction(model);
    }

    return response.body;
  }

  Future<dynamic> getContent(String table, [bool autosave = true]) async {
    init();
    int tableId = tables[table] ?? 0;

    if (tableId <= 0) return false;

    var response = await RestClient().get('$tableId/?size=200');
    if (response.statusCode != 200) Get.toNamed('/error');

    var json = _jsonDecoded(response.body);

    var results = json['results'];

    if (autosave == true) {
      final repositoryMap = {
        'area': AreaRepository().put,
        'business': BusinessRepository().put,
        'funding_program': FundingProgramRepository().put,
        'login': LoginRepository().put,
        'measure_types': MeasureRepository().put,
        'measure_general': MeasureGeneralRepository().put,
        'measure_details': MeasureDetailsRepository().put,
        'measure_types_details': MeasureTypesDetailsRepository().put,
      };

      var repositoryFunction = repositoryMap[table];
      if (repositoryFunction == null) return false;

      for (var item in results) {
        var model = _createModelFromJson(table, item);
        repositoryFunction(model);
      }
    }
    return results;
  }

  dynamic _createModelFromJson(String table, Map<String, dynamic> json) {
    switch (table) {
      case 'area':
        return Area.fromJson(json);
      case 'business':
        return Business.fromJson(json);
      case 'measure_types':
        final measureType = MeasureTypes.fromJson(json);
        listMeasures.add(measureType.toListMeasure());
        return measureType;
      case 'measure_general':
        final measureGeneral = MeasureGeneral.fromJson(json);
        listMeasures.add(measureGeneral.toListMeasure());
        return measureGeneral;
      case 'measure_details':
        return MeasureDetails.fromJson(json);
      case 'measure_types_details':
        return MeasureTypesDetails.fromJson(json);
      case 'funding_program':
        return FundingProgram.fromJson(json);
      case 'login':
        return Login.fromJson(json);
      default:
        return null;
    }
  }

  dynamic _jsonDecoded(String input) {
    return jsonDecode(utf8.decode(input.runes.toList()));
  }
}
