import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import '../constants.dart';

import 'dish_washer.dart';
import 'plug.dart';
import 'temp_humid.dart';
import 'thermostat.dart';
import 'washing_machine.dart';

class Category {
  Category(this.name) : devices = [];

  final String name;
  List<Device> devices;

  static Future<List<Category>> fetch_ids_only() async {
    final response = await http.get(Uri.parse("${Constants.BASE_URL}/devices"));

    if (response.statusCode != 200) {
      throw Exception("Failed to fetch devices");
    }

    final List<Category> categories = [];

    final Map<String, List<dynamic>> json =
        Map.castFrom(jsonDecode(jsonDecode(response.body)));

    for (final MapEntry<String, List<dynamic>> entry in json.entries) {
      final Category category = Category(entry.key);

      for (final dynamic device_info_dyn in entry.value) {
        final Map<String, dynamic> deviceInfo = device_info_dyn;

        category.devices
            .add(DeviceIdOnly(deviceInfo['id'], deviceInfo['desc']));
      }

      if (category.devices.isNotEmpty) {
        categories.add(category);
      }
    }

    return categories;
  }

  static Future<List<Category>> fetch() async {
    final response = await http.get(Uri.parse("${Constants.BASE_URL}/devices"));

    if (response.statusCode != 200) {
      throw Exception("Failed to fetch devices");
    }

    final List<Category> categories = [];

    final Map<String, List<dynamic>> json =
        Map.castFrom(jsonDecode(jsonDecode(response.body)));

    // create plugs
    {
      final Category category = Category('plugs');
      final List<dynamic> plugs = json['plugs']!;

      for (final dynamic device_info_dyn in plugs) {
        final Map<String, dynamic> deviceInfo = device_info_dyn;

        category.devices.add(await Plug.create(deviceInfo));
      }

      categories.add(category);
    }

    // create thermostat
    {
      final Category category = Category('thermostat');
      final List<dynamic> thermostats = json['thermostat']!;

      for (final dynamic device_info_dyn in thermostats) {
        final Map<String, dynamic> deviceInfo = device_info_dyn;

        category.devices.add(await Thermostat.create(deviceInfo));
      }

      categories.add(category);
    }

    // create temperature_and_humidity
    {
      final Category category = Category('temperature_and_humidity');
      final List<dynamic> temperatureAndHumidities =
          json['temperature_and_humidity']!;

      for (final dynamic device_info_dyn in temperatureAndHumidities) {
        final Map<String, dynamic> deviceInfo = device_info_dyn;

        category.devices.add(await TemperatureHumidity.create(deviceInfo));
      }

      categories.add(category);
    }

    // create dish_washer
    {
      final Category category = Category('dish_washer');
      final List<dynamic> dishWasher = json['dish_washer']!;

      for (final dynamic device_info_dyn in dishWasher) {
        final Map<String, dynamic> deviceInfo = device_info_dyn;

        category.devices.add(await DishWasher.create(deviceInfo));
      }

      categories.add(category);
    }

    // create washing_machines
    {
      final Category category = Category('washing_machines');
      final List<dynamic> washingMachines = json['washing_machines']!;

      for (final dynamic device_info_dyn in washingMachines) {
        final Map<String, dynamic> deviceInfo = device_info_dyn;

        category.devices.add(await WashingMachine.create(deviceInfo));
      }

      categories.add(category);
    }

    return categories;
  }

  String Name() {
    return name
        .split('_')
        .map((s) => "${s[0].toUpperCase()}${s.substring(1)}")
        .join(' ');
  }
}

class CategoryWidget extends StatelessWidget {

  const CategoryWidget({super.key, required this.category});
  final Category category;

  @override
  Widget build(BuildContext context) {
    return Wrap(
      spacing: 25,
      runSpacing: 25,
      children: category.devices
          .map((device) => device.create_widget(context))
          .toList(),
    );
  }
}

abstract class Device {
  Widget create_widget(BuildContext context);
}

class DeviceIdOnly extends Device {
  DeviceIdOnly(this.device_id, this.device_descriptor);

  final String device_id;
  final String? device_descriptor;

  @override
  Widget create_widget(BuildContext context) {
    throw UnimplementedError();
  }
}