from copy import copy

from efootprint.builders.hardware.boavizta_cloud_server import BoaviztaCloudServer
from efootprint.builders.services.service_base_class import Service
from efootprint.core.hardware.edge.edge_device import EdgeDevice
from efootprint.core.hardware.edge.edge_component import EdgeComponent
from efootprint.core.hardware.edge.edge_ram_component import EdgeRAMComponent
from efootprint.core.hardware.edge.edge_cpu_component import EdgeCPUComponent
from efootprint.core.hardware.edge.edge_workload_component import EdgeWorkloadComponent
from efootprint.builders.hardware.edge.edge_appliance import EdgeAppliance, EdgeApplianceComponent
from efootprint.builders.hardware.edge.edge_computer import EdgeComputer, EdgeComputerRAMComponent, EdgeComputerCPUComponent
from efootprint.core.hardware.edge.edge_storage import EdgeStorage
from efootprint.core.hardware.server_base import ServerBase
from efootprint.core.usage.edge.edge_function import EdgeFunction
from efootprint.core.usage.edge.recurrent_edge_component_need import RecurrentEdgeComponentNeed
from efootprint.core.usage.edge.recurrent_edge_storage_need import RecurrentEdgeStorageNeed
from efootprint.builders.usage.edge.recurrent_edge_process import (
    RecurrentEdgeProcess, RecurrentEdgeProcessRAMNeed, RecurrentEdgeProcessCPUNeed,
    RecurrentEdgeProcessStorageNeed)
from efootprint.core.usage.edge.edge_usage_journey import EdgeUsageJourney
from efootprint.core.usage.edge.edge_usage_pattern import EdgeUsagePattern
from efootprint.core.usage.edge.recurrent_edge_device_need import RecurrentEdgeDeviceNeed
from efootprint.core.usage.edge.recurrent_server_need import RecurrentServerNeed
from efootprint.builders.usage.edge.recurrent_edge_workload import RecurrentEdgeWorkload, RecurrentEdgeWorkloadNeed
from efootprint.core.usage.usage_journey_step import UsageJourneyStep
from efootprint.core.usage.usage_journey import UsageJourney
from efootprint.core.hardware.device import Device
from efootprint.core.country import Country
from efootprint.core.usage.usage_pattern import UsagePattern
from efootprint.core.hardware.storage import Storage
from efootprint.core.hardware.gpu_server import GPUServer
from efootprint.core.hardware.server import Server
from efootprint.builders.services.video_streaming import VideoStreaming, VideoStreamingJob
from efootprint.core.usage.job import Job, JobBase, GPUJob
from efootprint.core.hardware.network import Network
from efootprint.core.system import System
from efootprint.builders.external_apis.external_api_base_class import ExternalAPI, ExternalAPIServer
from efootprint.builders.external_apis.ecologits.ecologits_external_api import (
    EcoLogitsGenAIExternalAPIJob, EcoLogitsGenAIExternalAPI, EcoLogitsGenAIExternalAPIServer)
# Import timeseries so they get registered in ExplainableObject registry and can be parsed from json
from efootprint.builders import timeseries


SERVICE_CLASSES = [VideoStreaming]
SERVICE_JOB_CLASSES = [VideoStreamingJob]
EXTERNAL_API_SERVER_CLASSES = [EcoLogitsGenAIExternalAPIServer]
EXTERNAL_API_CLASSES = [EcoLogitsGenAIExternalAPI]
EXTERNAL_API_JOB_CLASSES = [EcoLogitsGenAIExternalAPIJob]
SERVER_CLASSES = [Server, GPUServer]
SERVER_BUILDER_CLASSES = [BoaviztaCloudServer]
EDGE_COMPONENT_CLASSES = [EdgeRAMComponent, EdgeCPUComponent, EdgeWorkloadComponent, EdgeStorage]
EDGE_COMPUTER_COMPONENT_CLASSES = [EdgeComputerRAMComponent, EdgeComputerCPUComponent, EdgeApplianceComponent]
RECURRENT_EDGE_COMPONENT_NEED_CLASSES = [
    RecurrentEdgeComponentNeed, RecurrentEdgeProcessRAMNeed, RecurrentEdgeProcessCPUNeed,
    RecurrentEdgeProcessStorageNeed, RecurrentEdgeWorkloadNeed]
RECURRENT_EDGE_DEVICE_NEED_BUILDER_CLASSES = [RecurrentEdgeProcess, RecurrentEdgeWorkload]
EDGE_DEVICE_BUILDER_CLASSES = [EdgeAppliance, EdgeComputer]


ALL_EFOOTPRINT_CLASSES = (
        [UsageJourneyStep, UsageJourney, Device, Country, UsagePattern]
        + [EdgeUsageJourney, EdgeFunction, EdgeUsagePattern, RecurrentEdgeStorageNeed]
        + EDGE_COMPONENT_CLASSES + EDGE_COMPUTER_COMPONENT_CLASSES + [EdgeDevice] + EDGE_DEVICE_BUILDER_CLASSES
        + SERVICE_CLASSES + SERVER_BUILDER_CLASSES + EXTERNAL_API_CLASSES
        + [Job, GPUJob] + [RecurrentEdgeDeviceNeed, RecurrentServerNeed] + RECURRENT_EDGE_COMPONENT_NEED_CLASSES
        + RECURRENT_EDGE_DEVICE_NEED_BUILDER_CLASSES + SERVICE_JOB_CLASSES + EXTERNAL_API_JOB_CLASSES
        + [Network] + SERVER_CLASSES + EXTERNAL_API_SERVER_CLASSES + [Storage, System])

CANONICAL_COMPUTATION_ORDER = [
    Country,
    UsagePattern, UsageJourney, UsageJourneyStep, Device,
    EdgeUsagePattern, EdgeUsageJourney, EdgeFunction,
    RecurrentEdgeDeviceNeed, RecurrentServerNeed,
    RecurrentEdgeComponentNeed, EdgeComponent,
    EdgeDevice, Service, JobBase, Network, ExternalAPI, ServerBase, ExternalAPIServer, Storage, System]

ALL_CANONICAL_CLASSES_DICT = {cls.__name__: cls for cls in CANONICAL_COMPUTATION_ORDER}
ALL_CONCRETE_EFOOTPRINT_CLASSES_DICT = {cls.__name__: cls for cls in ALL_EFOOTPRINT_CLASSES}
ALL_EFOOTPRINT_CLASSES_DICT = copy(ALL_CONCRETE_EFOOTPRINT_CLASSES_DICT)
ALL_EFOOTPRINT_CLASSES_DICT.update(ALL_CANONICAL_CLASSES_DICT)

SANKEY_COLUMNS = [
    [System],
    [Country],
    [UsagePattern, EdgeUsagePattern],
    [UsageJourney, EdgeUsageJourney],
    [EdgeFunction, UsageJourneyStep],
    [RecurrentEdgeDeviceNeed, RecurrentServerNeed],
    [JobBase, RecurrentEdgeComponentNeed],
    [Device, EdgeDevice, Network, ExternalAPI, ServerBase, ExternalAPIServer, Storage],
]

# Classes that appear only as breakdown children (via footprint_breakdown_by_source), not as intermediate traversal nodes
SANKEY_BREAKDOWN_ONLY_CLASSES = [EdgeComponent]

OBJECT_CATEGORIES = {
    "Servers": [ServerBase],
    "Storage": [Storage],
    "ExternalAPIs": [ExternalAPI],
    "Network": [Network],
    "Devices": [Device],
    "EdgeDevices": [EdgeDevice],
}
