import React, { useState } from 'react';

import { getImportsString, getPropsString } from '../helpers';

import Playground from '../Playground/Playground';
import { Button, Stack, Step, StepButton, StepLabel, Stepper, Typography } from '@/mui/components';

const steps = [...Array(5).keys()].map((value) => `Step ${value + 1}`);

function StepperSection() {
  const [activeStep, setActiveStep] = useState(0);
  const [completedStepIndexes, setCompletedStepIndexes] = useState(new Set());
  const [skippedStepsIndexes, setSkippedStepsIndexes] = useState(new Set());

  const isBackAllowed = activeStep === 0;
  const isNextAllowed = activeStep === steps.length - 1;
  const isStepSkipped = skippedStepsIndexes.has(activeStep);
  const isStepCompleted = completedStepIndexes.has(activeStep);

  const completedStep = [...completedStepIndexes].map((stepIndex) => steps[stepIndex]);
  const skippedSteps = [...skippedStepsIndexes].map((stepIndex) => steps[stepIndex]);
  const finishedSteps = [...completedStep, ...skippedSteps];
  const notFinishedSteps = steps.filter((s) => !finishedSteps.includes(s));
  const isAllStepsFinished = notFinishedSteps.length === 0;

  const handleBack = () => setActiveStep((prevActiveStep) => prevActiveStep - 1);
  const handleNext = () => setActiveStep((prevActiveStep) => prevActiveStep + 1);

  const handleSkip = () => {
    setSkippedStepsIndexes((prevSkipped) => {
      const newSkipped = new Set(prevSkipped.values());
      newSkipped.add(activeStep);
      return newSkipped;
    });

    if (activeStep < steps.length - 1) {
      handleNext();
    }
  };

  const handleComplete = () => {
    setCompletedStepIndexes((prevCompleted) => {
      const newCompleted = new Set(prevCompleted.values());
      newCompleted.add(activeStep);
      return newCompleted;
    });

    if (activeStep < steps.length - 1) {
      handleNext();
    }
  };

  const handleReset = () => {
    setActiveStep(0);
    setSkippedStepsIndexes(new Set());
    setCompletedStepIndexes(new Set());
  };

  return (
    <Stack spacing={4} sx={{ width: '100%' }}>
      <Stack spacing={2} sx={{ width: '100%' }}>
        <Typography variant="subtitle1">Linear stepper</Typography>
        <Playground
          initialState={[
            {
              type: 'select',
              stateId: 'orientation',
              options: ['horizontal', 'vertical'],
              selected: 'horizontal',
            },
            {
              type: 'checkbox',
              stateId: 'alternativeLabel',
              selected: false,
            },
            {
              type: 'checkbox',
              stateId: 'optionalSteps',
              selected: false,
            },
            {
              type: 'checkbox',
              stateId: 'failedSteps',
              selected: false,
            },
          ]}
          renderCallback={(state) => {
            const importsListString = getImportsString([[['Stepper', 'Step', 'StepLabel']]]);

            const { optionalSteps, failedSteps, ...restState } = state;
            const propsString = getPropsString(restState);

            return {
              component: (
                <Stepper
                  orientation={state.orientation}
                  alternativeLabel={state.alternativeLabel}
                  sx={{ width: '100%' }}
                >
                  {steps.map((label) => {
                    const labelProps = {
                      optional: undefined,
                      error: undefined,
                    };

                    if (state.optionalSteps) {
                      labelProps.optional = <Typography variant="caption">Optional</Typography>;
                    }

                    if (state.failedSteps) {
                      labelProps.optional = (
                        <Typography variant="caption" color="error">
                          Alert message
                        </Typography>
                      );
                      labelProps.error = true;
                    }

                    return (
                      <Step key={label}>
                        <StepLabel {...labelProps}>{label}</StepLabel>
                      </Step>
                    );
                  })}
                </Stepper>
              ),
              code: `${importsListString}
const steps = ${JSON.stringify(steps)};

<Stepper${propsString}>
  {steps.map((label) => {${
    optionalSteps
      ? `
    const labelProps = {
      optional: <Typography variant="caption">Optional</Typography>,
    };
`
      : ''
  }${
    failedSteps
      ? `
    const labelProps = {
      optional: <Typography variant="caption" color="error">Alert message</Typography>;
      error: true,
    };
`
      : ''
  }
    return (
      <Step key={label}>
        <StepLabel${optionalSteps || failedSteps ? ' {...labelProps}' : ''}>
          {label}
        </StepLabel>
      </Step>
    );
  })}
</Stepper>
`,
            };
          }}
          onChange={(nextState, id, value, setState) => {
            if (id === 'optionalSteps' && value) {
              setState({
                ...nextState,
                failedSteps: false,
              });
            } else if (id === 'failedSteps' && value) {
              setState({
                ...nextState,
                optionalSteps: false,
              });
            }
          }}
        />
      </Stack>
      <Stack spacing={2} sx={{ width: '100%' }}>
        <Typography variant="subtitle1">Non-linear stepper</Typography>
        <Playground
          initialState={[
            {
              type: 'select',
              stateId: 'orientation',
              options: ['horizontal', 'vertical'],
              selected: 'horizontal',
            },
            {
              type: 'checkbox',
              stateId: 'alternativeLabel',
              selected: false,
            },
            {
              type: 'checkbox',
              stateId: 'optionalSteps',
              selected: false,
            },
            {
              type: 'checkbox',
              stateId: 'failedSteps',
              selected: false,
            },
          ]}
          renderCallback={(state) => {
            const importsListString = getImportsString([[['Stepper', 'Step', 'StepButton', 'StepLabel']]]);

            const { optionalSteps, failedSteps, ...restState } = state;
            const propsString = getPropsString(restState);

            return {
              component: (
                <Stepper
                  orientation={state.orientation}
                  alternativeLabel={state.alternativeLabel}
                  activeStep={activeStep}
                  nonLinear
                  sx={{ width: '100%' }}
                >
                  {steps.map((label, index) => {
                    const buttonProps = {
                      optional: undefined,
                    };
                    const labelProps = {
                      optional: undefined,
                      error: undefined,
                    };

                    if (state.optionalSteps) {
                      buttonProps.optional = <Typography variant="caption">Optional</Typography>;
                    }

                    if (state.failedSteps) {
                      buttonProps.optional = (
                        <Typography variant="caption" color="error">
                          Alert message
                        </Typography>
                      );
                      labelProps.error = true;
                    }

                    return (
                      <Step key={label}>
                        <StepButton {...buttonProps} onClick={() => setActiveStep(index)}>
                          <StepLabel {...labelProps}>{label}</StepLabel>
                        </StepButton>
                      </Step>
                    );
                  })}
                </Stepper>
              ),
              code: `${importsListString}
const steps = ${JSON.stringify(steps)};

const [activeStep, setActiveStep] = useState(0);

<Stepper${propsString}
  activeStep={activeStep}
  nonLinear
>
  {steps.map((label, index) => {${
    optionalSteps
      ? `
    const buttonProps = {
      optional: <Typography variant="caption">Optional</Typography>,
    };
`
      : ''
  }${
    failedSteps
      ? `
    const buttonProps = {
      optional: <Typography variant="caption" color="error">Alert message</Typography>;
    };
    const labelProps = {
      error: true,
    };
`
      : ''
  }
    <Step key={label}>
      <StepButton${optionalSteps || failedSteps ? ' {...buttonProps}' : ''} onClick={() => setActiveStep(index)}>
        <StepLabel${failedSteps ? ' {...labelProps}' : ''}>{label}</StepLabel>
      </StepButton>
    </Step>
  })}
</Stepper>
`,
            };
          }}
          onChange={(nextState, id, value, setState) => {
            if (id === 'optionalSteps' && value) {
              setState({
                ...nextState,
                failedSteps: false,
              });
            } else if (id === 'failedSteps' && value) {
              setState({
                ...nextState,
                optionalSteps: false,
              });
            }
          }}
        />
      </Stack>
      <Stack spacing={2} sx={{ width: '100%' }}>
        <Typography variant="subtitle1">Custom actions</Typography>
        <Playground
          initialState={[
            {
              type: 'select',
              stateId: 'orientation',
              options: ['horizontal', 'vertical'],
              selected: 'horizontal',
            },
          ]}
          renderCallback={(state) => {
            const props = {
              ...state,
            };
            const importsListString = getImportsString([[['Stepper', 'Step', 'StepButton', 'StepLabel']]]);

            const propsString = getPropsString(props);

            return {
              component: (
                <Stack spacing={4} sx={{ width: '100%' }}>
                  <Stepper orientation={state.orientation} activeStep={activeStep} nonLinear sx={{ width: '100%' }}>
                    {steps.map((label, index) => {
                      const stepProps = {
                        completed: completedStepIndexes.has(index),
                      };

                      return (
                        <Step {...stepProps} key={label}>
                          <StepButton onClick={() => setActiveStep(index)}>
                            <StepLabel>{label}</StepLabel>
                          </StepButton>
                        </Step>
                      );
                    })}
                  </Stepper>
                  <Stack direction="column">
                    <Typography>Step info:</Typography>
                    <Typography>{`skipped: ${isStepSkipped}`}</Typography>
                    <Typography>{`completed: ${isStepCompleted}`}</Typography>
                  </Stack>
                  <Stack direction="column">
                    <Typography>Stepper info:</Typography>
                    <Typography>{`skipped: ${skippedSteps}`}</Typography>
                    <Typography>{`completed: ${completedStep}`}</Typography>
                    <Typography>{`not finished: ${notFinishedSteps}`}</Typography>
                  </Stack>
                  <Stack spacing={2} direction="row" justifyContent="flex-end" alignItems="center">
                    <Button variant="outlined" disabled={isBackAllowed} onClick={handleBack} sx={{ mr: 'auto' }}>
                      Back
                    </Button>
                    <Button variant="outlined" disabled={isNextAllowed} onClick={handleNext}>
                      Next
                    </Button>
                    <Button disabled={isStepSkipped || isStepCompleted} onClick={handleSkip}>
                      Skip
                    </Button>
                    <Button disabled={isStepSkipped || isStepCompleted} onClick={handleComplete}>
                      Complete Step
                    </Button>
                    <Button disabled={!isAllStepsFinished} onClick={handleReset}>
                      Reset
                    </Button>
                  </Stack>
                </Stack>
              ),
              code: `${importsListString}
const steps = ${JSON.stringify(steps)};

const [activeStep, setActiveStep] = useState(0);
const [completedStepIndexes, setCompletedStepIndexes] = useState(new Set());
const [skippedStepsIndexes, setSkippedStepsIndexes] = useState(new Set());

const isBackAllowed = activeStep === 0;
const isNextAllowed = activeStep === steps.length - 1;
const isStepSkipped = skippedStepsIndexes.has(activeStep);
const isStepCompleted = completedStepIndexes.has(activeStep);

const completedStep = [...completedStepIndexes].map((stepIndex) => steps[stepIndex]);
const skippedSteps = [...skippedStepsIndexes].map((stepIndex) => steps[stepIndex]);
const finishedSteps = [...completedStep, ...skippedSteps];
const notFinishedSteps = steps.filter((s) => !finishedSteps.includes(s));
const isAllStepsFinished = notFinishedSteps.length === 0;

const handleBack = () => setActiveStep((prevActiveStep) => prevActiveStep - 1);
const handleNext = () => setActiveStep((prevActiveStep) => prevActiveStep + 1);

const handleSkip = () => {
  setSkippedSteps((prevSkipped) => {
    const newSkipped = new Set(prevSkipped.values());
    newSkipped.add(activeStep);
    return newSkipped;
  });

  if (activeStep < steps.length - 1) {
    handleNext();
  }
};

const handleComplete = () => {
  setCompletedSteps((prevCompleted) => {
    const newCompleted = new Set(prevCompleted.values());
    newCompleted.add(activeStep);
    return newCompleted;
  });

  if (activeStep < steps.length - 1) {
    handleNext();
  }
};

const handleReset = () => {
  setActiveStep(0);
  setSkippedSteps(new Set());
  setCompletedSteps(new Set());
};

<Stack spacing={4} sx={{ width: '100%' }}>
  <Stepper
   ${propsString}
    activeStep={activeStep}
    nonLinear
    sx={{ width: '100%' }}
  >
    {steps.map((label, index) => {
      const stepProps = {
        completed: completedSteps.has(index),
      };

      return (
        <Step {...stepProps} key={label}>
          <StepButton onClick={() => setActiveStep(index)}>
            <StepLabel>{label}</StepLabel>
          </StepButton>
        </Step>
      );
    })}
  </Stepper>
  <Stack direction="column">
    <Typography>Step info:</Typography>
    <Typography>{\`skipped: ${isStepSkipped}\`}</Typography>
    <Typography>{\`completed: ${isStepCompleted}\`}</Typography>
  </Stack>
  <Stack direction="column">
    <Typography>Stepper info:</Typography>
    <Typography>{\`skipped: ${skippedSteps}\`}</Typography>
    <Typography>{\`completed: ${completedStep}\`}</Typography>
    <Typography>{\`not finished: ${notFinishedSteps}\`}</Typography>
  </Stack>
  <Stack spacing={2} direction="row" justifyContent="flex-end" alignItems="center">
    <Button variant="outlined" disabled={isBackAllowed} onClick={handleBack} sx={{ mr: 'auto' }}>
      Back
    </Button>
    <Button variant="outlined" disabled={isNextAllowed} onClick={handleNext}>
      Next
    </Button>
    <Button disabled={isStepSkipped || isStepCompleted} onClick={handleSkip}>
      Skip
    </Button>
    <Button disabled={isStepSkipped || isStepCompleted} onClick={handleComplete}>
      Complete Step
    </Button>
    <Button disabled={!isAllStepsFinished} onClick={handleReset}>
      Reset
    </Button>
  </Stack>
</Stack>
`,
            };
          }}
        />
      </Stack>
    </Stack>
  );
}

export default StepperSection;
