import styled from '@emotion/styled';
import React, { memo, useEffect, useState } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import Switch from '@/components/switch/Switch';
import { Tooltip } from '@/components/tooltip/Tooltip';
import { useContextSelector } from '@/hooks/useContextSelector';
import { InfoIcon } from '@/icons';
import { allowOnlyNumbers } from '@/utils/utils';

import CreateFormContext from '../../v2/CreateFormContext';
import { ConditionTypes } from '../../v2/types';
import CreateCard from './CreateCard';
import CreateSlider from './CreateSlider';

const DEFAULT_GPT_CFG = 4;
const DEFAULT_DIFFUSION_CFG = 1.5;

const VoxPersonaContent = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  color: var(--color-foreground-primary);
`;

const VoxPersonaInfo = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
`;

const VoxPersonaTitle = styled.span`
  font-size: 14px;
  font-weight: 500;
`;

const VoxPersonaSliders = styled.div`
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px;
  border-top: 1px solid var(--color-border-primary);
`;

const SliderWrapper = styled.div<{ disabled?: boolean }>`
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  opacity: ${({ disabled }) => (disabled ? 0.5 : 1)};
`;

const SliderLabel = styled.div`
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  min-width: 100px;
  font-size: 12px;
  font-weight: 500;
`;

const SliderReadout = styled.div`
  font-size: 12px;
  font-weight: 500;
  color: var(--color-foreground-primary);
  text-align: right;
  min-width: 30px;
  cursor: pointer;
  user-select: none;

  &:hover {
    opacity: 0.8;
  }
`;

const EditableInput = styled.input`
  font-size: 12px;
  font-weight: 500;
  color: var(--color-foreground-primary);
  text-align: right;
  background: transparent;
  border: none;
  outline: none;
  width: 30px;
  padding: 0;
  margin: 0;
  font-family: inherit;
`;

const VoxPersonaCard: React.FC = memo(function VoxPersonaCard() {
  const { session } = useStores();
  const untimedConditions = useContextSelector(
    CreateFormContext,
    (context) => context.state.global.untimedConditions
  );
  const voxPersonaCondition = useContextSelector(
    CreateFormContext,
    (context) =>
      context.state.global.untimedConditions[ConditionTypes.VOX_PERSONA]
  );
  const setState = useContextSelector(
    CreateFormContext,
    (context) => context.setState
  );

  const voxPersonaEnabled = voxPersonaCondition?.enabled ?? false;
  const gptCfg = voxPersonaCondition?.gptCfg ?? DEFAULT_GPT_CFG;
  const diffusionCfg =
    voxPersonaCondition?.diffusionCfg ?? DEFAULT_DIFFUSION_CFG;
  // Local state for sliders
  const [localGptCfg, setLocalGptCfg] = useState(gptCfg);
  const [localDiffusionCfg, setLocalDiffusionCfg] = useState(diffusionCfg);

  // Editing state for input fields
  const [editingGptCfg, setEditingGptCfg] = useState(false);
  const [editingDiffusionCfg, setEditingDiffusionCfg] = useState(false);
  const [inputGptCfg, setInputGptCfg] = useState(gptCfg.toString());
  const [inputDiffusionCfg, setInputDiffusionCfg] = useState(
    diffusionCfg.toString()
  );

  useEffect(() => {
    setLocalGptCfg(gptCfg);
    setInputGptCfg(gptCfg.toString());
  }, [gptCfg]);

  useEffect(() => {
    setLocalDiffusionCfg(diffusionCfg);
    setInputDiffusionCfg(diffusionCfg.toString());
  }, [diffusionCfg]);

  // Only show when vox-persona feature flag is enabled
  const { enabled: isVoxPersonaEnabled } =
    session.isFeatureAllowed('vox-persona');
  if (!isVoxPersonaEnabled) {
    return null;
  }

  // Only show when a persona is loaded
  const hasPersona = !!untimedConditions[ConditionTypes.PERSONA]?.[0];
  if (!hasPersona) {
    return null;
  }

  // Update function that avoids stale closures by reading current state
  const updateVoxPersonaCondition = (
    updates: Partial<{
      enabled: boolean;
      gptCfg: number;
      diffusionCfg: number;
    }>
  ) => {
    setState((prev) => {
      const currentCondition =
        prev.global.untimedConditions[ConditionTypes.VOX_PERSONA];
      const crowVoxModel = session.billingModels?.find(
        (model) => model.name === 'Crow Vox'
      );
      return {
        ...prev,
        global: {
          ...prev.global,
          model:
            updates.enabled && crowVoxModel !== undefined
              ? crowVoxModel.external_key
              : prev.global.model,
          untimedConditions: {
            ...prev.global.untimedConditions,
            [ConditionTypes.VOX_PERSONA]: {
              enabled: currentCondition?.enabled ?? false,
              gptCfg: currentCondition?.gptCfg ?? DEFAULT_GPT_CFG,
              diffusionCfg:
                currentCondition?.diffusionCfg ?? DEFAULT_DIFFUSION_CFG,
              ...updates,
            },
          },
        },
      };
    });
  };

  const toggleVoxPersona = () => {
    updateVoxPersonaCondition({ enabled: !voxPersonaEnabled });
  };

  const setGptCfg = (value: number) => {
    setLocalGptCfg(value);
    updateVoxPersonaCondition({ gptCfg: value });
  };

  const setDiffusionCfg = (value: number) => {
    setLocalDiffusionCfg(value);
    updateVoxPersonaCondition({ diffusionCfg: value });
  };

  const handleGptCfgEdit = (
    inputValue: string,
    setEditing: (editing: boolean) => void,
    min: number,
    max: number
  ) => {
    const numValue = parseFloat(inputValue);
    if (!isNaN(numValue)) {
      const clampedValue = Math.max(min, Math.min(max, numValue));
      setGptCfg(clampedValue);
    }
    setEditing(false);
  };

  const handleGptCfgKeyDown = (
    e: React.KeyboardEvent,
    setEditing: (editing: boolean) => void,
    inputValue: string,
    min: number,
    max: number
  ) => {
    if (e.key === 'Enter') {
      const numValue = parseFloat(inputValue);
      if (!isNaN(numValue)) {
        const clampedValue = Math.max(min, Math.min(max, numValue));
        setGptCfg(clampedValue);
      }
      setEditing(false);
    } else if (e.key === 'Escape') {
      setEditing(false);
    }
  };

  const handleDiffusionCfgEdit = (
    inputValue: string,
    setEditing: (editing: boolean) => void,
    min: number,
    max: number
  ) => {
    const numValue = parseFloat(inputValue);
    if (!isNaN(numValue)) {
      const clampedValue = Math.max(min, Math.min(max, numValue));
      setDiffusionCfg(clampedValue);
    }
    setEditing(false);
  };

  const handleDiffusionCfgKeyDown = (
    e: React.KeyboardEvent,
    setEditing: (editing: boolean) => void,
    inputValue: string,
    min: number,
    max: number
  ) => {
    if (e.key === 'Enter') {
      const numValue = parseFloat(inputValue);
      if (!isNaN(numValue)) {
        const clampedValue = Math.max(min, Math.min(max, numValue));
        setDiffusionCfg(clampedValue);
      }
      setEditing(false);
    } else if (e.key === 'Escape') {
      setEditing(false);
    }
  };

  return (
    <CreateCard collapsible={false}>
      <VoxPersonaContent>
        <VoxPersonaInfo>
          <VoxPersonaTitle>Vox Persona</VoxPersonaTitle>
          <Tooltip
            label={
              'Condition on the voice of the persona. Only works with Vox models.'
            }
          >
            <InfoIcon className='h-4 w-4 opacity-50' />
          </Tooltip>
        </VoxPersonaInfo>
        <Switch checked={voxPersonaEnabled} onChange={toggleVoxPersona} small />
      </VoxPersonaContent>
      <VoxPersonaSliders>
        <SliderWrapper disabled={!voxPersonaEnabled}>
          <SliderLabel>
            <span>GPT CFG</span>
            <Tooltip label='GPT CFG parameter. Set higher to make the voice more similar to the persona, but risk artifacts and unstable results.'>
              <InfoIcon className='h-3 w-3 opacity-50' />
            </Tooltip>
          </SliderLabel>
          <CreateSlider
            value={(localGptCfg - 1) / 9} // Convert 1-10 to 0-1 for slider display
            disabled={!voxPersonaEnabled}
            defaultValue={(DEFAULT_GPT_CFG - 1) / 9} // Default 4 converted to 0-1 for slider display
            onChange={(value) =>
              voxPersonaEnabled && setLocalGptCfg(value * 9 + 1)
            }
            onCommit={(value) => voxPersonaEnabled && setGptCfg(value * 9 + 1)}
          />
          {editingGptCfg && voxPersonaEnabled ? (
            <EditableInput
              type='text'
              value={inputGptCfg}
              onChange={(e) => {
                const value = e.target.value;
                if (allowOnlyNumbers(value)) {
                  setInputGptCfg(value);
                }
              }}
              onBlur={() =>
                handleGptCfgEdit(inputGptCfg, setEditingGptCfg, 1, 10)
              }
              onKeyDown={(e) =>
                handleGptCfgKeyDown(e, setEditingGptCfg, inputGptCfg, 1, 10)
              }
              autoFocus
            />
          ) : (
            <SliderReadout
              onDoubleClick={() => voxPersonaEnabled && setEditingGptCfg(true)}
              style={{ cursor: voxPersonaEnabled ? 'pointer' : 'default' }}
            >
              {localGptCfg.toFixed(2)}
            </SliderReadout>
          )}
        </SliderWrapper>

        <SliderWrapper disabled={!voxPersonaEnabled}>
          <SliderLabel>
            <span>Diffusion CFG</span>
            <Tooltip label='Diffusion CFG parameter. Set higher to make the voice more similar to the persona, but risk artifacts and unstable results.'>
              <InfoIcon className='h-3 w-3 opacity-50' />
            </Tooltip>
          </SliderLabel>
          <CreateSlider
            value={(localDiffusionCfg - 1) / 9} // Convert 1-10 to 0-1 for slider display
            disabled={!voxPersonaEnabled}
            defaultValue={(DEFAULT_DIFFUSION_CFG - 1) / 9} // Default 2 converted to 0-1 for slider display
            onChange={(value) =>
              voxPersonaEnabled && setLocalDiffusionCfg(value * 9 + 1)
            }
            onCommit={(value) =>
              voxPersonaEnabled && setDiffusionCfg(value * 9 + 1)
            }
          />
          {editingDiffusionCfg && voxPersonaEnabled ? (
            <EditableInput
              type='text'
              value={inputDiffusionCfg}
              onChange={(e) => {
                const value = e.target.value;
                if (allowOnlyNumbers(value)) {
                  setInputDiffusionCfg(value);
                }
              }}
              onBlur={() =>
                handleDiffusionCfgEdit(
                  inputDiffusionCfg,
                  setEditingDiffusionCfg,
                  1,
                  10
                )
              }
              onKeyDown={(e) =>
                handleDiffusionCfgKeyDown(
                  e,
                  setEditingDiffusionCfg,
                  inputDiffusionCfg,
                  1,
                  10
                )
              }
              autoFocus
            />
          ) : (
            <SliderReadout
              onDoubleClick={() =>
                voxPersonaEnabled && setEditingDiffusionCfg(true)
              }
              style={{ cursor: voxPersonaEnabled ? 'pointer' : 'default' }}
            >
              {localDiffusionCfg.toFixed(2)}
            </SliderReadout>
          )}
        </SliderWrapper>
      </VoxPersonaSliders>
    </CreateCard>
  );
});

export default VoxPersonaCard;
