import { useMemo, useState } from 'react';
import { useParams } from 'react-router';

import { Box, Button, Typography } from '@mui/material';

import { ModuleInputForm, useModuleInputDraft } from '@/components/Build/components/ModuleInputForm';
import Spinner from '@/components/common/Spinner';
import { skipToken } from '@reduxjs/toolkit/query';

import {
  useGetDeployedProjectQuery,
  useGetGroupModuleInputsQuery,
  useGetProjectModulesInputQuery,
  useGetProjectModulesQuery,
  useRenderModuleInputMutation,
  useSaveModuleInputMutation
} from '../../store/groupModulesApi';

const GroupModuleInputData = () => {
  const { id: groupId, moduleName } = useParams<{ id: string; moduleName: string }>();
  const { data: project } = useGetDeployedProjectQuery();
  const { data: modules = [], isFetching: isModulesFetching } = useGetProjectModulesQuery(project?.id ?? skipToken);

  const module = modules.find(added => (added.isExternal ? added.encodedName : added.name) === moduleName);
  const { data: moduleDefaultInput, isFetching } = useGetProjectModulesInputQuery(
    project && module && moduleName ? { projectId: project.id, moduleName, encodedName: !!module.isExternal } : skipToken
  );

  const { data: savedEntries = [], isFetching: isSavedFetching } = useGetGroupModuleInputsQuery(groupId ?? skipToken);
  const savedEntry = savedEntries.find(entry => entry.meta?.moduleName === moduleName);

  const spec = useMemo(() => {
    if (savedEntry?.meta.input?.length) {
      return savedEntry.meta.input;
    }
    return moduleDefaultInput?.input_spec?.length ? moduleDefaultInput.input_spec.map(({ response: _response, ...item }) => item) : null;
  }, [moduleDefaultInput, savedEntry]);

  const { input, onChange, commit, reset, unsupported } = useModuleInputDraft(spec);
  const [editing, setEditing] = useState(false);
  const [renderModuleInput, { isLoading: isRendering }] = useRenderModuleInputMutation();
  const [saveModuleInput, { isLoading: isSaving }] = useSaveModuleInputMutation();

  if (!moduleName) {
    return <Typography sx={{ m: 2 }}>Select a module to see its input data.</Typography>;
  }
  if (isModulesFetching || isFetching || isSavedFetching) {
    return <Spinner />;
  }
  if (!module) {
    return <Typography sx={{ m: 2 }}>This module is not added to the project.</Typography>;
  }

  const onSaveClick = () => {
    if (!project || !groupId || !input) {
      return;
    }
    renderModuleInput({ projectId: project.id, moduleName, input })
      .unwrap()
      .then(({ augment }) => saveModuleInput({ augment, entryId: savedEntry?.id, groupId, input, moduleName, projectId: project.id }).unwrap())
      .then(() => {
        commit();
        setEditing(false);
      })
      .catch(() => undefined);
  };

  const onCancelClick = () => {
    reset();
    setEditing(false);
  };

  return (
    <Box>
      <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', px: 2, py: 1.5, borderBottom: 1, borderColor: 'divider' }}>
        <Typography variant="h3">{module.name}</Typography>
        {editing ? (
          <Box sx={{ display: 'flex', gap: 1 }}>
            <Button variant="outlined" color="inherit" onClick={onCancelClick}>
              Cancel
            </Button>
            <Button variant="contained" color="secondary" loading={isRendering || isSaving} onClick={onSaveClick}>
              Save
            </Button>
          </Box>
        ) : (
          <Button variant="outlined" color="inherit" disabled={!input || unsupported} onClick={() => setEditing(true)}>
            Edit
          </Button>
        )}
      </Box>
      <Box sx={{ px: 2, pb: 2 }}>
        <ModuleInputForm input={input} loaded editing={editing} onChange={onChange} />
      </Box>
    </Box>
  );
};

export default GroupModuleInputData;
