import { useReactFlow } from '@xyflow/react';
import { t } from 'i18next';
import { Split } from 'lucide-react';
import { memo, useEffect } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';

import {
  ActionType,
  FlowOperationRequest,
  FlowOperationType,
  flowStructureUtil,
  FlowVersion,
  isNil,
  RouterAction,
  RouterExecutionType,
} from '@activepieces/shared';

import { FormField, FormItem } from '../../../../components/ui/form';
import { Label } from '../../../../components/ui/label';
import {
  Select,
  SelectValue,
  SelectTrigger,
  SelectContent,
  SelectItem,
} from '../../../../components/ui/select';
import { useBuilderStateContext } from '../../builder-hooks';
import { flowCanvasUtils } from '../../flow-canvas/utils/flow-canvas-utils';
import { BranchSettings } from '../branch-settings';

import { BranchesList } from './branches-list';
import BranchesToolbar from './branches-toolbar';

export const RouterSettings = memo(({ readonly }: { readonly: boolean }) => {
  const [
    step,
    applyOperation,
    setSelectedBranchIndex,
    selectedBranchIndex,
    addOperationListener,
    removeOperationListener,
  ] = useBuilderStateContext((state) => [
    flowStructureUtil.getActionOrThrow(
      state.selectedStep!,
      state.flowVersion.trigger,
    ) as RouterAction,
    state.applyOperation,
    state.setSelectedBranchIndex,
    state.selectedBranchIndex,
    state.addOperationListener,
    state.removeOperationListener,
  ]);
  const { fitView } = useReactFlow();

  const { control, setValue, formState } =
    useFormContext<Omit<RouterAction, 'children' | 'nextAction'>>();

  //To validate array items we need to use form.trigger()
  const { insert, remove, move } = useFieldArray({
    control,
    name: 'settings.branches',
  });
  const form = useFormContext<Omit<RouterAction, 'children' | 'nextAction'>>();
  const deleteBranch = (index: number) => {
    applyOperation({
      type: FlowOperationType.DELETE_BRANCH,
      request: {
        stepName: step.name,
        branchIndex: index,
      },
    });

    setSelectedBranchIndex(null);
    fitView(flowCanvasUtils.createFocusStepInGraphParams(step.name));
  };

  useEffect(() => {
    const operationListener = (
      flowVersion: FlowVersion,
      operation: FlowOperationRequest,
    ) => {
      switch (operation.type) {
        case FlowOperationType.DELETE_BRANCH: {
          if (operation.request.stepName !== step.name) {
            return;
          }
          remove(operation.request.branchIndex);
          break;
        }
        case FlowOperationType.DUPLICATE_BRANCH:
        case FlowOperationType.ADD_BRANCH: {
          if (operation.request.stepName !== step.name) return;
          const updatedStep = flowStructureUtil.getActionOrThrow(
            operation.request.stepName,
            flowVersion.trigger,
          );
          if (updatedStep.type !== ActionType.ROUTER) {
            console.error(
              `Trying to duplicate a branch on a none router step! ${operation.request.stepName}`,
            );
            return;
          }
          const branch =
            updatedStep.settings.branches[operation.request.branchIndex];
          if (operation.type === FlowOperationType.DUPLICATE_BRANCH) {
            insert(operation.request.branchIndex + 1, {
              ...branch,
              branchName: `${branch.branchName} Copy`,
            });
          } else {
            insert(
              updatedStep.settings.branches.length - 1,
              flowStructureUtil.createBranch(
                `Branch ${updatedStep.settings.branches.length}`,
                undefined,
              ),
            );
          }
          form.trigger();
          break;
        }
        case FlowOperationType.MOVE_BRANCH: {
          if (operation.request.stepName !== step.name) return;
          move(
            operation.request.sourceBranchIndex,
            operation.request.targetBranchIndex,
          );
          break;
        }
      }
    };

    addOperationListener(operationListener);
    return () => removeOperationListener(operationListener);
  }, []);

  return (
    <>
      {isNil(selectedBranchIndex) && (
        <FormField
          control={control}
          name="settings.executionType"
          render={({ field }) => (
            <FormItem>
              <Label>{t('Execute')}</Label>
              <Select
                disabled={field.disabled}
                onValueChange={field.onChange}
                value={field.value}
              >
                <SelectTrigger>
                  <SelectValue placeholder={t('Execute')} />
                </SelectTrigger>

                <SelectContent>
                  <SelectItem
                    value={`${RouterExecutionType.EXECUTE_FIRST_MATCH}`}
                  >
                    {t('Only the first (left) matching branch')}
                  </SelectItem>
                  <SelectItem
                    value={`${RouterExecutionType.EXECUTE_ALL_MATCH}`}
                  >
                    {t('All matching paths from left to right')}
                  </SelectItem>
                </SelectContent>
              </Select>
            </FormItem>
          )}
        ></FormField>
      )}

      {isNil(selectedBranchIndex) && (
        <div className="mt-4">
          <div className="flex gap-2 mb-2 items-center">
            <Split className="w-4 h-4 rotate-180"></Split>
            <Label>{t('Branches')}</Label>
          </div>

          <BranchesList
            errors={(formState.errors.settings?.branches as unknown[]) ?? []}
            readonly={readonly}
            step={step}
            branchNameChanged={(index, name) => {
              setValue(`settings.branches.${index}.branchName` as const, name, {
                shouldValidate: true,
              });
            }}
            deleteBranch={deleteBranch}
            moveBranch={({ sourceIndex, targetIndex }) => {
              applyOperation({
                type: FlowOperationType.MOVE_BRANCH,
                request: {
                  stepName: step.name,
                  sourceBranchIndex: sourceIndex,
                  targetBranchIndex: targetIndex,
                },
              });
            }}
            duplicateBranch={(index) => {
              applyOperation({
                type: FlowOperationType.DUPLICATE_BRANCH,
                request: {
                  stepName: step.name,
                  branchIndex: index,
                },
              });
              setSelectedBranchIndex(index + 1);
            }}
            setSelectedBranchIndex={(index) => {
              setSelectedBranchIndex(index);
              if (step.children[index]) {
                fitView(
                  flowCanvasUtils.createFocusStepInGraphParams(
                    step.children[index].name,
                  ),
                );
              } else {
                fitView(
                  flowCanvasUtils.createFocusStepInGraphParams(
                    `${step.name}-big-add-button-${step.name}-branch-${index}-start-edge`,
                  ),
                );
              }
            }}
          ></BranchesList>
          {!readonly && (
            <div className="mt-2">
              <BranchesToolbar
                addButtonClicked={() => {
                  applyOperation({
                    type: FlowOperationType.ADD_BRANCH,
                    request: {
                      stepName: step.name,
                      branchIndex: step.settings.branches.length - 1,
                      branchName: `Branch ${step.settings.branches.length}`,
                    },
                  });

                  setSelectedBranchIndex(step.settings.branches.length - 1);
                }}
              ></BranchesToolbar>
            </div>
          )}
        </div>
      )}

      {!isNil(selectedBranchIndex) && (
        <BranchSettings
          readonly={readonly}
          key={`settings.branches[${selectedBranchIndex}].conditions`}
          branchIndex={selectedBranchIndex}
        ></BranchSettings>
      )}
    </>
  );
});

RouterSettings.displayName = 'RouterSettings';
