import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { revalidateSystemIcon } from '@/lib/revalidate-icon';
import { cn } from '@/lib/utils';
import {
  Setting,
  SettingComponentEnum,
  SettingTypeEnum,
} from '@hed-hog/api-types';
import { useApp } from '@hed-hog/next-app-provider';
import { Eye, EyeOff, Upload } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useEffect, useRef, useState } from 'react';

type SettingFieldProps = {
  setting: Setting;
  className?: string;
};

export const SettingField = ({ setting, className }: SettingFieldProps) => {
  const t = useTranslations('core.Configurations');
  const { showToastHandler, setSettingValue, request } = useApp();
  const component =
    setting.component?.replaceAll('_', '-') || SettingComponentEnum.INPUT_TEXT;
  const [localValue, setLocalValue] = useState(setting.value);
  const [showSecretValue, setShowSecretValue] = useState(false);
  const debounceTimerRef = useRef<NodeJS.Timeout | undefined>(undefined);
  const isTextInputRef = useRef<boolean>(false);

  const isThemeSetting = (slug: string) => {
    return slug.startsWith('theme-') || slug === 'menu-width';
  };

  const applyThemeSettings = async () => {
    try {
      const response: any = await request({
        url: '/setting/initial',
        method: 'GET',
      });

      const newSettings = response.data?.setting || {};
      localStorage.setItem('settings', JSON.stringify(newSettings));
      window.dispatchEvent(new CustomEvent('hedhog:settings-change'));
    } catch (error) {
      console.error('Error applying theme settings:', error);
    }
  };

  useEffect(() => {
    if (!isTextInputRef.current) return;

    if (debounceTimerRef.current) {
      clearTimeout(debounceTimerRef.current);
    }

    debounceTimerRef.current = setTimeout(() => {
      if (localValue !== setting.value) {
        setSettingValue(setting.slug, localValue)
          .then(async () => {
            showToastHandler('success', t('settingUpdated'));

            if (['icon-url'].includes(setting.slug)) {
              await revalidateSystemIcon();
              showToastHandler('success', t('iconRevalidated'));
              window.location.reload();
            }

            if (isThemeSetting(setting.slug)) {
              await applyThemeSettings();
            }
          })
          .catch(() => {
            showToastHandler('error', t('settingUpdateFailed'));
          });
      }
    }, 500);

    return () => {
      if (debounceTimerRef.current) {
        clearTimeout(debounceTimerRef.current);
      }
    };
  }, [localValue]);

  const handleChangeValue = (newValue: any, immediate = false) => {
    setLocalValue(newValue);
    if (immediate) {
      setSettingValue(setting.slug, newValue)
        .then(async () => {
          showToastHandler('success', t('settingUpdated'));
          if (isThemeSetting(setting.slug)) {
            await applyThemeSettings();
          }
        })
        .catch(() => {
          showToastHandler('error', t('settingUpdateFailed'));
        });
    }
  };

  const getParsedValue = () => {
    const value = localValue;
    if (value === undefined || value === null) return value;

    switch (setting.type) {
      case SettingTypeEnum.NUMBER:
        return typeof value === 'number' ? value : parseFloat(value) || 0;
      case SettingTypeEnum.BOOLEAN:
        return typeof value === 'boolean'
          ? value
          : value === 'true' || value === '1';
      case SettingTypeEnum.ARRAY:
      case SettingTypeEnum.JSON:
        try {
          return typeof value === 'string' ? JSON.parse(value) : value;
        } catch {
          return value;
        }
      default:
        return value;
    }
  };

  const formatValue = (val: any) => {
    switch (setting.type) {
      case SettingTypeEnum.ARRAY:
      case SettingTypeEnum.JSON:
        return typeof val === 'string' ? val : JSON.stringify(val);
      case SettingTypeEnum.BOOLEAN:
        return val ? 'true' : 'false';
      case SettingTypeEnum.NUMBER:
        return val?.toString() || '0';
      default:
        return val;
    }
  };

  const parsedValue = getParsedValue();
  switch (component) {
    case SettingComponentEnum.INPUT_TEXT:
      isTextInputRef.current = true;
      return (
        <Input
          type="text"
          value={parsedValue || ''}
          onChange={(e) => handleChangeValue(formatValue(e.target.value))}
          className={cn(className, 'w-full min-w-0 bg-background md:min-w-50')}
        />
      );

    case SettingComponentEnum.INPUT_NUMBER:
      isTextInputRef.current = true;
      return (
        <Input
          type="number"
          value={parsedValue || 0}
          onChange={(e) =>
            handleChangeValue(formatValue(parseFloat(e.target.value) || 0))
          }
          className={cn(className, 'w-full min-w-0 bg-background md:min-w-50')}
        />
      );

    case SettingComponentEnum.INPUT_SECRET:
      isTextInputRef.current = true;
      return (
        <div className="relative w-full min-w-0 md:min-w-50">
          <Input
            type={showSecretValue ? 'text' : 'password'}
            value={parsedValue || ''}
            onChange={(e) => handleChangeValue(formatValue(e.target.value))}
            className={cn(
              className,
              'w-full min-w-0 bg-background pr-10 md:min-w-50'
            )}
          />
          <Button
            type="button"
            variant="ghost"
            size="icon"
            className="absolute right-1 top-1/2 h-8 w-8 -translate-y-1/2"
            onClick={() => setShowSecretValue((prev) => !prev)}
            aria-label={showSecretValue ? 'Hide password' : 'Show password'}
          >
            {showSecretValue ? (
              <EyeOff className="h-4 w-4" />
            ) : (
              <Eye className="h-4 w-4" />
            )}
          </Button>
        </div>
      );

    case SettingComponentEnum.INPUT_FILE:
      isTextInputRef.current = true;
      const fileInputRef = useRef<HTMLInputElement>(null);
      const [isUploading, setIsUploading] = useState(false);

      const handleFileUpload = async (
        e: React.ChangeEvent<HTMLInputElement>
      ) => {
        const file = e.target.files?.[0];
        if (!file) return;

        setIsUploading(true);
        try {
          const formData = new FormData();
          formData.append('file', file);

          const response: any = await request({
            url: '/file',
            method: 'POST',
            data: formData,
            headers: {
              'Content-Type': 'multipart/form-data',
            },
          });

          const fileId = response.data?.id;

          if (!fileId) {
            throw new Error('File ID not returned');
          }

          const openResponse: any = await request({
            url: `/file/open/${fileId}`,
            method: 'PUT',
          });

          const openUrl = openResponse?.data?.url;

          if (!openUrl) {
            throw new Error('Temporary open URL not returned');
          }

          const fileUrl =
            typeof openUrl === 'string' && openUrl.startsWith('http')
              ? openUrl
              : `${String(process.env.NEXT_PUBLIC_API_BASE_URL || '')}${openUrl}`;

          handleChangeValue(formatValue(fileUrl));
          showToastHandler('success', t('fileUploaded'));
        } catch (error) {
          showToastHandler('error', t('fileUploadFailed'));
        } finally {
          setIsUploading(false);
          if (fileInputRef.current) {
            fileInputRef.current.value = '';
          }
        }
      };

      return (
        <div className="flex w-full min-w-0 flex-col gap-2 md:min-w-50">
          {parsedValue && (
            <div>
              <img
                src={parsedValue || ''}
                alt={t('uploadedFileAlt')}
                className="max-w-full md:w-50"
              />
            </div>
          )}
          <div className="flex w-full min-w-0 items-center gap-2">
            <input
              ref={fileInputRef}
              type="file"
              onChange={handleFileUpload}
              className="hidden"
              id={`file-${setting.id}`}
            />
            <Button
              type="button"
              variant="outline"
              size="icon"
              onClick={() => fileInputRef.current?.click()}
              disabled={isUploading}
              className="shrink-0"
            >
              <Upload className="h-4 w-4" />
            </Button>
            <Input
              type="text"
              value={parsedValue || ''}
              onChange={(e) => handleChangeValue(formatValue(e.target.value))}
              className="min-w-0 flex-1 bg-background"
              placeholder={t('fileUrlPlaceholder')}
              disabled={isUploading}
            />
          </div>
        </div>
      );

    case SettingComponentEnum.SWITCH:
      return (
        <Switch
          checked={parsedValue || false}
          onCheckedChange={(checked) =>
            handleChangeValue(formatValue(checked), true)
          }
          className={cn(className)}
        />
      );

    case SettingComponentEnum.CHECKBOX:
      if (setting.type === SettingTypeEnum.ARRAY) {
        const options = setting.setting_list || [];
        const selectedValues: string[] = Array.isArray(parsedValue)
          ? parsedValue
          : [];
        return (
          <div
            className={cn(
              'flex w-full min-w-0 flex-col space-y-2 md:min-w-50',
              className
            )}
          >
            {options.map((option) => (
              <div key={option.id} className="flex items-center space-x-2">
                <Checkbox
                  className="bg-background"
                  checked={selectedValues.includes(option.value)}
                  onCheckedChange={(checked) => {
                    let newValues = [...selectedValues];
                    if (checked) {
                      newValues.push(option.value);
                    } else {
                      newValues = newValues.filter(
                        (val) => val !== option.value
                      );
                    }
                    handleChangeValue(formatValue(newValues), true);
                  }}
                />
                <Label>{option.value}</Label>
              </div>
            ))}
          </div>
        );
      }
      return (
        <Checkbox
          checked={parsedValue || false}
          onCheckedChange={(checked) =>
            handleChangeValue(formatValue(checked), true)
          }
          className={cn(className)}
        />
      );

    case SettingComponentEnum.COMBOBOX:
      const options = setting.setting_list || [];
      return (
        <Select
          value={parsedValue?.toString() || ''}
          onValueChange={(val) => handleChangeValue(formatValue(val), true)}
        >
          <SelectTrigger
            className={cn(
              'w-full min-w-0 bg-background md:min-w-50',
              className
            )}
          >
            <SelectValue placeholder={t('selectOption')} />
          </SelectTrigger>
          <SelectContent>
            {options.map((option) => (
              <SelectItem key={option.id} value={option.value}>
                {option.value}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      );

    case SettingComponentEnum.RADIO:
      const radioOptions = setting.setting_list || [];
      return (
        <RadioGroup
          value={parsedValue?.toString() || ''}
          onValueChange={(val) => handleChangeValue(formatValue(val), true)}
          className={cn(className, 'w-full min-w-0 md:min-w-50')}
        >
          {radioOptions.map((option) => (
            <div key={option.id} className="flex items-center space-x-2">
              <RadioGroupItem
                value={option.value}
                id={`radio-${option.id}`}
                className="bg-background"
              />
              <Label htmlFor={`radio-${option.id}`}>{option.value}</Label>
            </div>
          ))}
        </RadioGroup>
      );

    case SettingComponentEnum.COLOR_PICKER:
      isTextInputRef.current = true;
      return (
        <div className="flex w-full min-w-0 items-center gap-2 md:max-w-50">
          <Input
            type="color"
            value={parsedValue || '#000000'}
            onChange={(e) => handleChangeValue(formatValue(e.target.value))}
            className={cn(
              'h-10 w-10 border-none p-0 cursor-pointer',
              className
            )}
          />
          <Input
            type="text"
            value={parsedValue || '#000000'}
            onChange={(e) => handleChangeValue(formatValue(e.target.value))}
            className="flex-1 bg-background"
            placeholder="#000000"
            maxLength={7}
            minLength={7}
          />
        </div>
      );

    default:
      return (
        <Input
          type="text"
          value={parsedValue || ''}
          onChange={(e) => handleChangeValue(formatValue(e.target.value))}
          className={cn(className, 'bg-background')}
        />
      );
  }
};
