"use client";

import { useRef, useEffect, useState } from "react";
import mermaid from "mermaid";
import {
  Button,
  Card,
  Chip,
  Dialog,
  DialogActions,
  Tooltip,
  DialogContent,
  DialogContentText,
  DialogTitle,
  IconButton,
  List,
  TextField,
} from "@mui/material";
//Icons
import RefreshIcon from "@mui/icons-material/Refresh";
import ZoomInIcon from "@mui/icons-material/ZoomIn";
import ZoomOutIcon from "@mui/icons-material/ZoomOut";
import FullscreenIcon from "@mui/icons-material/Fullscreen";
import DownloadIcon from "@mui/icons-material/Download";
import ResetIcon from "@mui/icons-material/Autorenew";
import FilterAltIcon from "@mui/icons-material/FilterAlt";

// Custom Components
import { NoDataOverlay } from "../noDataOverlay";
import { LoadingOverlay } from "../join/loadingOverlay";

import { useGetAllEventmessages } from "@/api/eventmessages/eventmessages";
import { mutate } from "swr";

import { extractAllEventMessages, generateMermaidString } from "./helpers";
import CopyToClipboard from "../copy_to_clipboard";
import { formatDateTime, getGroupById } from "@/utils/helpers";

const SequenceDiagram = () => {
  const {
    data: eventMessagesData,
    isLoading: loadingEventMessages,
    swrKey: eventMessagesKeyFunc,
  } = useGetAllEventmessages();

  const mermaidRef: any = useRef(null);
  const [scale, setScale] = useState(1);
  const [openFilters, setOpenFilters] = useState(false);

  const [sequenceNr, setSequenceNr] = useState("");
  const hasData = eventMessagesData?.data;

  const mermaidString = generateMermaidString(eventMessagesData?.data);
  const allEventMessages = extractAllEventMessages(eventMessagesData?.data);

  useEffect(() => {
    if (!loadingEventMessages && hasData)
      mermaid.initialize({
        startOnLoad: false,
        securityLevel: "loose",
        sequence: {
          mirrorActors: true,
          showSequenceNumbers: true,
        },
      });

    if (mermaidRef.current) {
      mermaidRef.current.innerHTML = mermaidString;
      mermaid.init(undefined, mermaidRef.current);
    }
  }, [loadingEventMessages, hasData, mermaidString]);

  useEffect(() => {
    if (mermaidRef.current) {
      const svg = mermaidRef.current.querySelector("svg");
      if (svg) {
        svg.style.transform = `scale(${scale})`;
        svg.style.transformOrigin = "top left";
        mermaidRef.current.style.width = `${
          svg.getBoundingClientRect().width * scale
        }px`;
        mermaidRef.current.style.height = `${
          svg.getBoundingClientRect().height * scale
        }px`;
      }
    }
  }, [scale]);

  const onRefresh = () => {
    const eventMessagesKey =
      typeof eventMessagesKeyFunc === "function"
        ? eventMessagesKeyFunc()
        : eventMessagesKeyFunc;

    if (eventMessagesKey) {
      mutate(eventMessagesKey);
    }
  };

  const zoomIn = () => {
    setScale((scale) => scale * 1.1);
  };

  const zoomOut = () => {
    setScale((scale) => scale / 1.1);
  };

  const resetZoom = () => {
    setScale(1);
  };

  const viewInFullScreen = () => {
    if (mermaidRef.current) {
      const svg = mermaidRef.current.querySelector("svg");
      const serializer = new XMLSerializer();
      const svgBlob = new Blob([serializer.serializeToString(svg)], {
        type: "image/svg+xml",
      });
      const url = URL.createObjectURL(svgBlob);
      window.open(url, "_blank");
    }
  };

  const downloadAsPng = () => {
    if (mermaidRef.current) {
      const svg = mermaidRef.current.querySelector("svg");
      const svgData = new XMLSerializer().serializeToString(svg);

      // Create a canvas element to convert SVG to PNG
      const canvas = document.createElement("canvas");
      const svgSize = svg.getBoundingClientRect();
      canvas.width = svgSize.width;
      canvas.height = svgSize.height;
      const ctx = canvas.getContext("2d");
      const img = document.createElement("img");

      img.onload = () => {
        ctx?.drawImage(img, 0, 0);
        const pngData = canvas.toDataURL("image/png");

        // Trigger download
        const link = document.createElement("a");
        link.download = "sequence-diagram.png";
        link.href = pngData;
        link.click();
      };

      img.src =
        "data:image/svg+xml;base64," +
        btoa(unescape(encodeURIComponent(svgData)));
    }
  };

  const toggleFilters = () => {
    setOpenFilters((prevState) => !prevState);
  };

  const onSearchBySeqNumber = (e: any) => {
    setSequenceNr(e.target.value);
  };

  const isFilterMatch = (index: number) => {
    if (!sequenceNr) return true;

    const filterSeqNrInt = parseInt(sequenceNr, 10);
    return index + 1 === filterSeqNrInt;
  };

  if (loadingEventMessages)
    return <LoadingOverlay title="Loading Diagram" subtitle="Please wait..." />;

  return (
    <>
      <div className="flex flex-col items-end">
        {hasData ? (
          <>
            <div className="flex justify-end">
              <Tooltip placement="top" title="Filter Messages">
                <IconButton color="primary" onClick={toggleFilters}>
                  <FilterAltIcon />
                </IconButton>
              </Tooltip>
              <Tooltip placement="top" title="Refresh Diagram">
                <IconButton color="primary" onClick={onRefresh}>
                  <RefreshIcon />
                </IconButton>
              </Tooltip>
              <Tooltip title="Zoom In" placement="top">
                <IconButton color="primary" onClick={zoomIn}>
                  <ZoomInIcon />
                </IconButton>
              </Tooltip>
              <Tooltip title="Zoom Out" placement="top">
                <IconButton color="primary" onClick={zoomOut}>
                  <ZoomOutIcon />
                </IconButton>
              </Tooltip>
              <Tooltip title="Reset" placement="top">
                <IconButton color="primary" onClick={resetZoom}>
                  <ResetIcon />
                </IconButton>
              </Tooltip>
              <Tooltip title="View in Fullscreen" placement="top">
                <IconButton color="primary" onClick={viewInFullScreen}>
                  <FullscreenIcon />
                </IconButton>
              </Tooltip>
              <Tooltip title="Download as PNG" placement="top">
                <IconButton color="primary" onClick={downloadAsPng}>
                  <DownloadIcon />
                </IconButton>
              </Tooltip>
            </div>
            <div className="w-full p-2.5">
              <div className="mermaid" ref={mermaidRef}></div>
            </div>
          </>
        ) : (
          <div className="flex w-full justify-center">
            <NoDataOverlay label="No Activity yet" />
          </div>
        )}
      </div>

      {openFilters && (
        <>
          <Dialog
            open={openFilters}
            keepMounted
            fullWidth
            maxWidth="lg"
            onClose={toggleFilters}
          >
            <DialogTitle>All Event Messages</DialogTitle>
            <DialogContent>
              <DialogContentText>
                <div className="flex items-center gap-2.5">
                  <label>Search by Sequence # </label>
                  <TextField
                    onChange={onSearchBySeqNumber}
                    size="small"
                    variant="outlined"
                  />
                </div>
                <List className="w-full" component="nav">
                  {allEventMessages
                    .filter((_: any, index: number) => {
                      return isFilterMatch(index);
                    })
                    .map((message: any, index: number) => {
                      const {
                        msg_type_name: msgType,
                        des_name,
                        src_name,
                        group,
                        group_id,
                        timestamp,
                        src_did,
                        des_did,
                        // msg, TODO: Need to use the content inside the msg to display in the diagram
                      } = message;

                      const formattedTimeStamp = formatDateTime(timestamp);
                      const { groupIcon: IconComponent, groupName } =
                        getGroupById(group);

                      return (
                        <div
                          key={index}
                          style={{ marginBottom: 12 }}
                          className="flex items-center gap-5"
                        >
                          <Chip label={sequenceNr ? sequenceNr : ++index} />
                          <Card style={{ padding: 10 }} className="w-full">
                            <div
                              style={{ marginBottom: 12 }}
                              className="flex justify-between"
                            >
                              <div>
                                <span
                                  style={{
                                    marginBottom: 12,
                                    fontWeight: "bold",
                                  }}
                                  className="flex items-center gap-2"
                                >
                                  {IconComponent} {groupName}{" "}
                                  <Chip label={msgType} />
                                </span>
                                <span>
                                  Sender: {src_name} <Chip label={src_did} /> |{" "}
                                </span>
                                <span>
                                  Receiver: {des_name} <Chip label={des_did} />{" "}
                                  |{" "}
                                </span>
                                <span>Group: {group} | </span>
                                <span>Group ID: {group_id}</span>
                              </div>
                              <span>{formattedTimeStamp}</span>
                            </div>
                            <span className="font-bold">
                              Event Message {sequenceNr ? sequenceNr : index++}
                            </span>
                            <div
                              className="mt-4 flex"
                              style={{
                                border: "1px solid #f1f1f1",
                                borderRadius: 5,
                              }}
                            >
                              <pre className="flex-1 p-2">
                                {JSON.stringify(message, null, 2)}
                              </pre>
                              <div className="shrink-0 p-2">
                                <CopyToClipboard textToCopy={message} />
                              </div>
                            </div>
                          </Card>
                        </div>
                      );
                    })}
                </List>
              </DialogContentText>
            </DialogContent>
            <DialogActions className="p-4">
              <Button variant="contained" onClick={toggleFilters}>
                Close
              </Button>
            </DialogActions>
          </Dialog>
        </>
      )}
    </>
  );
};

export default SequenceDiagram;
