import 'package:flutter/material.dart';
import 'package:oc_front/core/services/enum_service.dart';
import 'package:oc_front/models/abstract.dart';
import 'package:oc_front/models/resources/resources.dart';

class ProcessingItem extends AbstractItem<ProcessingPricing, ProcessingPartnership, ProcessingInstance, ProcessingItem> {
    // special attributes
  int? infrastructureEnum;
  bool isService = false;
  bool openSource = false;
  String? license;
  String? maturity;
  ProcessingUsage? usage;  
  
  ProcessingItem({
    this.infrastructureEnum,
    this.isService = false,
    this.openSource = false,
    this.license,
    this.maturity,
    this.usage,
  }): super();  

  @override String get topic => "processing";

  @override deserialize(dynamic data) {
    try { data = data as Map<String, dynamic>;
    } catch (e) { return ProcessingItem(); }   
    var w = ProcessingItem(
      infrastructureEnum: data.containsKey("infrastructure") ? EnumService.get("infrastructure", data["infrastructure"]) : null,
      isService: data.containsKey("is_service") && data["is_service"] != null ? data["is_service"] : false,
      openSource: data.containsKey("open_source") && data["open_source"] != null ? data["open_source"] : false,
      license: data.containsKey("license") && data["license"] != null ? data["license"] : null,
      maturity: data.containsKey("maturity") && data["maturity"] != null ? data["maturity"] : null,
      usage: data.containsKey("usage") && data["usage"] != null ? ProcessingUsage().deserialize(data["usage"]) : null,
    );
    w.mapFromJSON(data, ProcessingInstance());
    if (w.logo != null) { // get image dimensions
      var image = Image.network(w.logo!);
      image.image
        .resolve(const ImageConfiguration())
        .addListener(
            ImageStreamListener(
                (ImageInfo info, bool _) {
                  w.width = info.image.width.toDouble();
                  w.height = info.image.height.toDouble();
                }));
    }
    return w;
  }

  @override
  Map<String, dynamic> infos() {
    return {
      "infrastructure": EnumService.enums["infrastructure"] != null 
      && EnumService.enums["infrastructure"]!["$infrastructureEnum"] != null ? 
      EnumService.enums["infrastructure"]!["$infrastructureEnum"] : infrastructureEnum,
      "is_service": isService,
      "open_source": openSource,
      "license": license,
      "maturity": maturity,
    };
  }

  @override Map<String, dynamic> serialize() {
    var obj = infos();
    obj["infrastructure"] = infrastructureEnum;
    obj["usage"] = usage?.serialize();
    obj.addAll(toJSON());
    return obj;
  }
}

class ProcessingAccess extends SerializerDeserializer<ProcessingAccess> {
  Containered? container;

  ProcessingAccess({
    this.container,
  });

  @override ProcessingAccess deserialize(dynamic json) {
    try {
      json = json as Map<String, dynamic>;
    } catch (e) {
      return ProcessingAccess();
    }
    return ProcessingAccess(
      container: json.containsKey("container") && json["container"] != null ? Containered().deserialize(json["container"]) : null,
    );
  }

  @override Map<String, dynamic> serialize() {
    return {
      "container": container?.serialize(),
    };
  }
}

class ProcessingInstance extends AbstractInstance<ProcessingPricing, ProcessingPartnership> {
  ProcessingAccess? access;
  ProcessingInstance(
    {this.access}
  ): super();

  @override
  ProcessingInstance deserialize(json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return ProcessingInstance(); }
    var w = ProcessingInstance();
    w.access = json.containsKey("access") && json["access"] != null ? ProcessingAccess().deserialize(json['access']) : null;
    w.mapFromJSON(json, ProcessingPartnership());
    return w;
  }

  @override
  Map<String, dynamic> serialize() {
    var obj = toJSON();
    obj["access"] = access?.serialize();
    return obj;
  }

  @override
  Map<String, dynamic> infos() {
    return {
      "inputs": toListJson(inputs),
      "outputs": toListJson(outputs),
    };
  } 
}

class ProcessingPartnership extends AbstractPartnerShip<ProcessingPricing> {
  ProcessingPartnership(): super();

  @override
  ProcessingPartnership deserialize(json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return ProcessingPartnership(); }
    var w = ProcessingPartnership();
    w.mapFromJSON(json, ProcessingPricing());
    return w;
  }

  @override
  Map<String, dynamic> serialize() {
    return toJSON();
  }
}

class ProcessingPricing extends AbstractPricing {
  @override ProcessingPricing deserialize(json) {
    var w = ProcessingPricing();
    w.mapFromJSON(json);
    return w;
  }
  @override
  Map<String, dynamic> serialize() {
    return toJSON();
  }
}

class ProcessingUsage extends SerializerDeserializer<ProcessingUsage> {
    Map<String,CPU> cpus = {};
    Map<String,GPU> gpus = {};
    RAM? ram;
    double? storageSize;
    String? hypothesis;
    String? scalingModel;

    ProcessingUsage({
      this.cpus = const {},
      this.gpus = const {},
      this.ram,
      this.storageSize,
      this.hypothesis,
      this.scalingModel,
    });

    @override
  ProcessingUsage deserialize(json) {
    return ProcessingUsage(
      cpus: json.containsKey("cpus") && json["cpus"] != null ? fromMapJson(json["cpus"], CPU()) : {},
      gpus: json.containsKey("gpus") && json["gpus"] != null ? fromMapJson(json["gpus"], GPU()) : {},
      ram: json.containsKey("ram") && json["ram"] != null ? RAM().deserialize(json["ram"]) : null,
      storageSize: json.containsKey("storage_size") && json["storage_size"] != null ? json["storage_size"]?.toDouble() : null,
      hypothesis: json.containsKey("hypothesis") && json["hypothesis"] != null ? json["hypothesis"] : null,
      scalingModel: json.containsKey("scaling_model") && json["scaling_model"] != null ? json["scaling_model"] : null,
    );
  }

  @override
  Map<String, dynamic> serialize() {
    return {
      "cpus": toMapJson(cpus),
      "gpus": toMapJson(gpus),
      "ram": ram?.serialize(),
      "storage_size": storageSize,
      "hypothesis": hypothesis,
      "scaling_model": scalingModel,
    };
  }

}

class CPU extends SerializerDeserializer<CPU> {
  CPU({
    this.cores,
    this.platform,
    this.architecture,
    this.minimumMemory,
    this.shared = false,
  });
  double? cores;
  String? platform;
  bool shared = false;
  String? architecture;
  double? minimumMemory;

  @override deserialize(dynamic json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return CPU(); }  
    return CPU(
      cores: json.containsKey("cores") && json["cores"] != null ? json["cores"]?.toDouble() : null,
      platform: json.containsKey("platform") && json["platform"] != null ? json["platform"] : null,
      architecture: json.containsKey("architecture") && json["architecture"] != null ? json["architecture"] : null,
      minimumMemory: json.containsKey("minimumMemory") && json["minimumMemory"] != null ? json["minimumMemory"]?.toDouble() : null,
      shared: json.containsKey("shared") && json["shared"] != null ? json["shared"] : false,
    );
  }
  @override Map<String, dynamic> serialize() => {
    "cores": cores,
    "platform": platform,
    "architecture": architecture,
    "minimumMemory": minimumMemory,
    "shared": shared,
  };
}
class GPU extends SerializerDeserializer<GPU> {
  GPU({
    this.cudaCores,
    this.memory,
    this.model,
    this.tensorCores,
  });
  double? cudaCores;
  double? memory;
  String? model;
  double? tensorCores;

  @override deserialize(dynamic json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return GPU(); }  
    return GPU(
      cudaCores: json.containsKey("cuda_cores") && json["cuda_cores"] != null ? json["cuda_cores"]?.toDouble() : null,
      memory: json.containsKey("memory") && json["memory"] != null ? json["memory"]?.toDouble() : null,
      model: json.containsKey("model") && json["model"] != null ? json["model"] : null,
      tensorCores: json.containsKey("tensor_cores") && json["tensor_cores"] != null ? json["tensor_cores"]?.toDouble() : null,
    );
  }
  @override Map<String, dynamic> serialize() => {
    "cuda_cores": cudaCores,
    "memory": memory,
    "model": model,
    "tensor_cores": tensorCores,
  };
}
class RAM extends SerializerDeserializer<RAM> {
  RAM({
    this.ecc = false,
    this.size,
  });
  bool ecc = false;
  double? size;

  @override deserialize(dynamic json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return RAM(); }  
    return RAM(
      ecc: json.containsKey("ecc") && json["ecc"] != null ? json["ecc"] : false,
      size: json.containsKey("size") && json["size"] != null ? json["size"]?.toDouble() : null,
    );
  }
  @override Map<String, dynamic> serialize() => {
    "ecc": ecc,
    "size": size,
  };
}

class Expose extends SerializerDeserializer<Expose> {
  Expose({
    this.PAT,
    this.port,
    this.path,
  });
  
  int? port;
  int? PAT;
  String? path;

  @override deserialize(dynamic json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return Expose(); }
    return Expose(
      port: json.containsKey("port") && json["port"] != null ? json["port"] : null,
      PAT: json.containsKey("PAT") && json["PAT"] != null ? json["PAT"] : null,
      path: json.containsKey("reverse") && json["reverse"] != null ? json["reverse"] : null,
    );
  }

  @override Map<String, dynamic> serialize() => {
    "port": port,
    "PAT": PAT,
    "reverse": path,
  };
}

class Containered extends SerializerDeserializer<Containered> {
  Containered({
    this.image,
    this.args,
    this.command,
    this.env,
    this.volumes,
    this.exposes = const [],
  }); 

  String? args;
  String? image;
  String? command;
  Map<String, dynamic>? env;
  Map<String, dynamic>? volumes;
  List<Expose> exposes = [];

  @override deserialize(dynamic json) {
    try { json = json as Map<String, dynamic>;
    } catch (e) { return Containered(); }
    return Containered(
      args: json.containsKey("args") && json["args"] != null ? json["args"] : null,
      image: json.containsKey("image") && json["image"] != null ? json["image"] : null,
      command: json.containsKey("command") && json["command"] != null ? json["command"] : null,
      env: json.containsKey("env") && json["env"] != null ? json["env"] : null,
      volumes: json.containsKey("volumes") && json["volumes"] != null ? json["volumes"] : null,
      exposes: json.containsKey("exposes") && json["exposes"] != null ? fromListJson(json["exposes"], Expose()) : [],
    );
  }
  @override Map<String, dynamic> serialize() {
    var w = {
      "args": args,
      "image": image,
      "command": command,
      "env": env,
      "volumes": volumes,
      "exposes": toListJson(exposes),
    };
    return w;
  }
}