import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:oc_front/core/models/workspace_local.dart';
import 'package:oc_front/core/services/perms_service.dart';
import 'package:oc_front/core/services/specialized_services/workflow_service.dart';
import 'package:oc_front/main.dart';
import 'package:oc_front/models/resources/compute.dart';
import 'package:oc_front/models/resources/data.dart';
import 'package:oc_front/models/resources/processing.dart';
import 'package:oc_front/models/resources/resources.dart';
import 'package:oc_front/models/resources/storage.dart';
import 'package:oc_front/models/resources/workflow.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/pages/abstract_page.dart';
import 'package:oc_front/pages/shared.dart';
import 'package:oc_front/widgets/dialog/shallow_creation.dart';
import 'package:oc_front/widgets/forms/resource_forms.dart';
import 'package:oc_front/widgets/forms/scheduler_forms.dart';
import 'package:oc_front/widgets/forms/storage_processing_link_forms.dart';
import 'package:oc_front/widgets/items/item_row.dart';
import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart';

Dashboard dash = Dashboard(name: "");
class WorkflowFactory implements AbstractFactory {
  @override GlobalKey getKey() { return key; }
  @override String? getSearch() { return ""; }
  @override void back(BuildContext context) { }
  static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>();
  @override bool searchFill() { return false; }
  @override Widget factory(GoRouterState state, List<String> args) { 
    String? id;
    try { id = state.pathParameters[args.first];
    } catch (e) { /**/ }
    return WorkflowPageWidget(id: id); 
  }
  @override void search(BuildContext context, bool special) { }
}
bool getAll = true;

// ignore: must_be_immutable
class WorkflowPageWidget extends StatefulWidget {
  String? id;
  WorkflowPageWidget ({ this.id }) : super(key: WorkflowFactory.key);
  @override WorkflowPageWidgetState createState() => WorkflowPageWidgetState();
  static void search(BuildContext context) { }
  static Widget factory() { return WorkflowPageWidget(); }
}
class WorkflowPageWidgetState extends State<WorkflowPageWidget> {
final WorflowService _service = WorflowService();
  Widget itemBuild(Object item) {
    var e = item as AbstractItem;
    return Tooltip( message: item.name ?? "",
      child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill) 
        : Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', 
      fit: BoxFit.fill));
  }
  Widget itemTooltipBuild(Object item) {
    var e = item as AbstractItem;
    return Container(color: Colors.white, child: ItemRowWidget(low: true, contextWidth: 290, item: e));
  }
  Widget getArrowForms(ArrowPainter? arrow) {
    if (arrow == null) { return Container(); }
    var from = dash.getElement(arrow.fromID);
    var to = dash.getElement(arrow.toID);
    if ((from?.element?.getType() == "storage" && to?.element?.getType() == "processing") 
    || (from?.element?.getType() == "processing" && to?.element?.getType() == "storage")) {
      return StorageProcessingLinkFormsWidget( dash: dash, item: arrow);
    }
    return Container();
  }
  List<Widget> getForms(FlowData? obj, String id) {
    var objAbs = obj as AbstractItem?;
    if (objAbs == null) { return []; }
    List<Widget> res = [ ResourceFormsWidget(item: objAbs, dash: dash, elementID: id) ];
    return [ Wrap( 
      alignment: WrapAlignment.center,
      children: [
      Container( padding: const EdgeInsets.all(10), width: 250, height: 60,
        decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
        child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [
          Text("ELEMENT INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
          Text("<general>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center),
      ])), 
      ...res
    ]) ];
  }

  Widget? getTopRight(FlowData? obj) {
    var objAbs = obj as AbstractItem?;
    if (objAbs == null) { return null; }
    if (objAbs.topic == "compute") {
      var instance = objAbs as ComputeItem;
      if (instance.infrastructureEnum != null) {
        if (instance.infrastructureEnum == 0) {
          return const Icon(FontAwesomeIcons.docker, size: 16);
        } else if (instance.infrastructureEnum == 1) {
          return const Icon(FontAwesomeIcons.lifeRing, size: 16);
        } else if (instance.infrastructureEnum == 2) {
          return const Icon(FontAwesomeIcons.cubes, size: 16);
        } else if (instance.infrastructureEnum == 3) {
          return const Icon(FontAwesomeIcons.hardDrive, size: 16);
        } else if (instance.infrastructureEnum == 4) {
          return const Icon(FontAwesomeIcons.v, size: 16);
        }
      }
    }
    return null;
  }

  Widget? getBottomLeftBadge(FlowData? obj) {
    var objAbs = obj as AbstractItem?;
    if (objAbs == null) { return null; }
    if (objAbs.topic == "processing" ) {
      return const  Icon(FontAwesomeIcons.gear, size: 16);
    } else if (objAbs.topic == "data" ) {
      return const Icon(FontAwesomeIcons.file, size: 16);
    } else if (objAbs.topic == "storage" ) {
      return const Icon(FontAwesomeIcons.database, size: 16);
    } else if (objAbs.topic == "compute" ) {
      return const Icon(FontAwesomeIcons.microchip, size: 16);
    } else if (objAbs.topic == "workflows" ) {
      return const Icon(FontAwesomeIcons.diagramProject, size: 16);
    }
    return null;
  }

  List<Widget> getDashInfoForms() {
    return [
      SchedulerFormsWidget(item: dash),
    ];
  }

  Future<void> loadDash(String selected) async {
    dash.shouldSave = false;
    dash.name = "";
    var name = "";
    if (selected.split("~").length > 1) {
      name = selected.split("~")[1];
      dash.id = selected.split("~")[0];
    } else {
      name = selected;
    }
    await _service.get(context, dash.id ?? "").then((value) async {
      if (value.data != null) {
        // ignore: use_build_context_synchronously
        await WorkspaceLocal.init(context, false);
        WorkspaceLocal.changeWorkspaceByName("${value.data?.name ?? ""}_workspace");
        dash.clear();
        dash.deserialize(value.data!.toDashboard(), false);
        Future.delayed(const Duration(seconds: 1), () {
          dash.name = name;
          dash.shouldSave = true;
          dash.selectedMenuKey.currentState?.setState(() { });
        });
      }
    });
  }

  Future<void> saveDash(String? id, BuildContext? context) async {
    if (id == null || !dash.isOpened || !dash.shouldSave || !PermsService.getPerm(Perms.WORKFLOW_EDIT)) { return; }
    var datas =  dash.elements.where( (e) => e.element?.serialize()["type"] == "data");
    var compute = dash.elements.where( (e) => e.element?.serialize()["type"] == "compute");
    var storage = dash.elements.where( (e) => e.element?.serialize()["type"] == "storage");
    var processing = dash.elements.where( (e) => e.element?.serialize()["type"] == "processing");
    var workflows = dash.elements.where( (e) => e.element?.serialize()["type"] == "workflow");
    var updateW = Workflow(
      name: dash.name,
      graph: Graph(),
      data: datas.map((e) => e.element?.getID()).toSet().toList(),
      compute: compute.map((e) => e.element?.getID()).toSet().toList(),
      storage: storage.map((e) => e.element?.getID()).toSet().toList(),
      processing: processing.map((e) => e.element?.getID()).toSet().toList(),
      workflows: workflows.map((e) => e.element?.getID()).toSet().toList(),
    );
    updateW.fromDashboard(dash.serialize());
    for (var item in (updateW.graph?.items.values ?? [] as List<GraphItem>)) {
      if (item.position == null) { continue; }
      item.position?.x = (item.position?.x ?? 0) + (item.width! / 2) + 7.5;
      item.position?.y = (item.position?.y ?? 0) + (item.height! / 2) + 7.5;
      for (var i in (updateW.graph?.links ?? [] as List<GraphLink>).where((element) => id == element.source?.id)) {
        i.source?.x = (i.source?.x ?? 0) + (item.width! / 2) + 7.5;
        i.source?.y = (i.source?.y ?? 0) + (item.width! / 2) + 7.5;
      }
      for (var i in (updateW.graph?.links ?? [] as List<GraphLink>).where((element) => id == element.destination?.id)) {
        i.destination?.x = (i.destination?.x ?? 0) + (item.width! / 2) + 7.5;
        i.destination?.y = (i.destination?.y ?? 0) + (item.width! / 2) + 7.5;
      }
    }
    updateW.graph?.zoom = dash.getZoomFactor();
    dash.addToHistory();
      _service.put(null, id, updateW.serialize(), {}).then( (e) async {
        dash.applyInfos(updateW.graph?.getEnvToUpdate() ?? {}, updateW.toDashboard());
        if (dash.addChange) {
          dash.addChange = false;
          // ignore: use_build_context_synchronously
          await WorkspaceLocal.init(context, false);
          WorkspaceLocal.changeWorkspaceByName("${dash.name}_workspace");
          dash.selectedLeftMenuKey.currentState?.setState(() { });
        }
      });  
  }

  FlowData? transformToData(Map<String, dynamic> data) {
    if (data["type"] == "data") { return DataItem().deserialize(data); }
    if (data["type"] == "compute") { return ComputeItem().deserialize(data); }
    if (data["type"] == "storage") { return StorageItem().deserialize(data); }
    if (data["type"] == "processing") { return ProcessingItem().deserialize(data); }
    if (data["type"] == "workflows") { return WorkflowItem().deserialize(data); }
    return null;
  }

  Widget onDashboardMenu(Dashboard dash) {
    return Container( padding: const EdgeInsets.only(left: 50),
                decoration: const BoxDecoration( border: Border( left: BorderSide( color: Colors.white ))),
                child: ShallowDropdownInputWidget(
                  filled: lightColor,
                  hintColor: Colors.grey.shade200,
                  color: Colors.white,
                  prefixIcon: Padding( padding: const EdgeInsets.only(right: 10), child: Icon(Icons.shopping_cart, color: Colors.grey.shade200)),
                  current: WorkspaceLocal.current,
                  width: 300,
                  all: () async => WorkspaceLocal.getWorkspacesShallow(),
                  type: CollaborativeAreaType.workspace,
                  change: (String? change) {
                    WorkspaceLocal.changeWorkspace(change.toString());
                  },
                  canLoad: (p0) => true,
                  load: (p0) async {
                    dash.isInfo = !dash.isInfo;
                    dash.flutterChartKey.currentState?.setState(() { });
                  },
                  tooltipLoad: "open workspace manager",
                  iconLoad: dash.isInfo ? Icons.remove_red_eye_outlined : Icons.remove_red_eye,
          ));
  }
  Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) {
    return ShallowCreationDialogWidget(
      canClose: () => dash.isOpened,
      context: context,
      load: (p0) async {
        dash.isOpened = true;
        if (dash.load != null) {
            WorkspaceLocal.changeWorkspaceByName(p0.split("~")[1]);  
            await dash.load!(p0);         
          } 
          dash.inDialog = false;
          dash.notifyListeners();
      },
      create: PermsService.getPerm(Perms.WORKFLOW_CREATE) ? (p0) async => await _service.post(context, p0, {}).then( (value) async {
          dash.clear();
          dash.id = value.data?.getID() ?? "";
          dash.name = value.data?.getName() ?? "";
          dash.inDialog = false;
          dash.notifyListeners();
          await WorkspaceLocal.init(context, true);
          dash.isOpened = true;
          Future.delayed(const Duration(seconds: 1), () {
            dash.load!("${dash.id}~${dash.name}");
          });
        }
      ) : null,
      maptoDropdown: (e) => DropdownMenuItem<String>(
                              value: "${e.id}~${e.name}",
                              child: Text(e.name),
                            ),
      type: CollaborativeAreaType.workflow,
      all: () async {
        List<Shallow> res = [];
        await _service.all(context).then(
          (e) {
            if (e.data != null) {
              res = e.data!.values.map((e) => Shallow(id: e["id"] ?? "", name: e["name"] ?? "")).toList();
            }
          }
        );
        return res;
      }
    );
  }
  @override Widget build(BuildContext context) {
    dash.load = loadDash;
    dash.save = saveDash;
    dash.dashColor = lightColor;
    dash.midDashColor = midColor;
    dash.transformToData = transformToData;
    dash.infoItemWidget = getForms;
    dash.infoLinkWidget = getArrowForms;
    dash.infoWidget = getDashInfoForms;
    dash.widthOffset = 50;
    dash.arrowStyleRules = [
      (dash) {
        for (var arrow in dash.arrows) {
          try {
            var from = dash.elements.firstWhere((element) => arrow.fromID.split("_")[0] == element.id).element;
            var to = dash.elements.firstWhere((element) => arrow.toID.split("_")[0] == element.id).element;
            if ((from is ProcessingItem && to is ComputeItem) || (to is ProcessingItem && from is ComputeItem)) {
              arrow.params.color = Colors.orange;
              arrow.params.dashSpace = 2;
              arrow.params.dashWidth = 2;
            } else if ((from is ProcessingItem && to is StorageItem) || (to is ProcessingItem && from is StorageItem)) {
              arrow.params.color = redColor;
              arrow.params.dashSpace = 2;
              arrow.params.dashWidth = 2;
            } else if ((from is ProcessingItem && to is DataItem) || (to is ProcessingItem && from is DataItem)) {
              arrow.params.color = Colors.blue;
              arrow.params.dashSpace = 2;
              arrow.params.dashWidth = 2;
            } else {
              arrow.params.color = Colors.black;
              arrow.params.dashSpace = 0;
              arrow.params.dashWidth = 0;
            }
          } catch (e) {
            arrow.params.color = Colors.black;
            arrow.params.dashSpace = 0;
            arrow.params.dashWidth = 0;
          }
        }
        return dash.arrows;
      }
    ];
    dash.saveRules = [
      (dash) {
        dash.error = null;
        
        return true;
      }
    ];
    return FlowChart<AbstractItem>(
                key: dash.flutterChartKey,
                itemLeftBottomBadges: getBottomLeftBadge,
                itemrightTopBadges: getTopRight,
                onDashboardAlertOpened: onDashboardAlertOpened,
                dashboard: dash,
                current: widget.id,
                itemWidget: itemBuild,
                menuWidget: onDashboardMenu,
                categories: const ["processing", "data", "compute", "storage", "workflows"],
                draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, false),
                itemWidgetTooltip: itemTooltipBuild,
                innerMenuWidth: 350,
                width: getMainWidth(context),
                height: getMainHeight(context),
                onNewConnection: (p1, p2) { },
                onDashboardTapped: (context, position) { },
                onScaleUpdate: (newScale) { },
                onDashboardSecondaryTapped: (context, position) { },
                onDashboardLongTapped: (context, position) { },
                onDashboardSecondaryLongTapped: (context, position) { },
                onElementLongPressed: (context, position, element) { },
                onElementSecondaryLongTapped: (context, position, element) { },
                onElementPressed: (context, position, element) {  },
                onElementSecondaryTapped: (context, position, element) { },
                onHandlerPressed: (context, position, handler, element) { },
                onHandlerLongPressed: (context, position, handler, element) { },
                onPivotSecondaryPressed: (context, pivot) { },
      );
  }
}