import React, { useCallback, useId, useRef, useState } from 'react';
import styled, { css } from 'styled-components';
import { HiCloudUpload } from 'react-icons/hi';
import { FilePreviewList } from './FilePreviewList';
import { ImageCropModal } from '../ImageCropModal/ImageCropModal';
import { useLocale } from '@/app/providers/LocaleProvider';
import {
  ATTACHMENT_ALLOWED_EXTENSIONS,
  ATTACHMENT_MAX_FILES,
  validateAttachmentFiles,
} from '@/features/tickets/constants/attachments';
import { isPreviewableImage } from '@/shared/hooks/useObjectUrls';

const Zone = styled.div<{ $active: boolean; $hasError: boolean }>`
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: ${({ theme }) => theme.spacing[3]};
  padding: ${({ theme }) => theme.spacing[10]} ${({ theme }) => theme.spacing[8]};
  border-radius: ${({ theme }) => theme.borderRadius.lg};
  border: 2px dashed
    ${({ theme, $hasError, $active }) =>
    $hasError
      ? theme.colors.error
      : $active
        ? theme.colors.primary
        : theme.colors.border};
  background: ${({ theme, $active }) =>
    $active
      ? `linear-gradient(165deg, ${theme.colors.primaryLight} 0%, ${theme.colors.surfaceInset} 100%)`
      : `linear-gradient(165deg, ${theme.colors.surfaceElevated} 0%, ${theme.colors.surfaceInset} 100%)`};
  cursor: pointer;
  transition:
    border-color ${({ theme }) => theme.transitions.fast},
    background-color ${({ theme }) => theme.transitions.fast},
    box-shadow ${({ theme }) => theme.transitions.fast},
    transform ${({ theme }) => theme.transitions.fast};

  @media (prefers-reduced-motion: reduce) {
    transition:
      border-color ${({ theme }) => theme.transitions.fast},
      background-color ${({ theme }) => theme.transitions.fast};
  }

  text-align: center;

  ${({ $active, theme }) =>
    $active &&
    css`
      box-shadow: ${theme.shadows.sm};
      transform: ${theme.motion.hoverLift};
    `}

  &:hover {
    border-color: ${({ theme, $hasError }) =>
    $hasError ? theme.colors.error : theme.colors.primary};
    background-color: ${({ theme }) => theme.colors.primaryLight};
  }

  &:focus-within {
    outline: 2px solid ${({ theme }) => theme.colors.primary};
    outline-offset: 2px;
  }
`;

const IconWrap = styled.span`
  width: 52px;
  height: 52px;
  border-radius: ${({ theme }) => theme.borderRadius.lg};
  background-color: ${({ theme }) => theme.colors.surface};
  color: ${({ theme }) => theme.colors.primary};
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: ${({ theme }) => theme.shadows.xs};
  transition: transform ${({ theme }) => theme.transitions.fast};

  ${Zone}:hover & {
    transform: scale(1.04);
  }

  svg {
    width: 26px;
    height: 26px;
  }
`;

const Title = styled.p`
  margin: 0;
  font-size: ${({ theme }) => theme.typography.fontSize.base};
  font-weight: ${({ theme }) => theme.typography.fontWeight.semibold};
  color: ${({ theme }) => theme.colors.text.primary};
  letter-spacing: ${({ theme }) => theme.typography.letterSpacing.tight};
`;

const Hint = styled.p`
  margin: 0;
  font-size: ${({ theme }) => theme.typography.fontSize.xs};
  color: ${({ theme }) => theme.colors.text.tertiary};
  max-width: 28rem;
  line-height: ${({ theme }) => theme.typography.lineHeight.relaxed};
`;

const ErrorText = styled.p`
  margin: ${({ theme }) => theme.spacing[2]} 0 0;
  font-size: ${({ theme }) => theme.typography.fontSize.xs};
  color: ${({ theme }) => theme.colors.error};
  text-align: start;
`;

const HiddenInput = styled.input`
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
`;

export interface FileUploadZoneProps {
  files: File[];
  onFilesChange: (files: File[]) => void;
  error?: string | null;
  disabled?: boolean;
  maxFiles?: number;
  enableImageCrop?: boolean;
  onImagePreview?: (file: File, url: string) => void;
}

export const FileUploadZone: React.FC<FileUploadZoneProps> = ({
  files,
  onFilesChange,
  error: externalError,
  disabled = false,
  maxFiles = ATTACHMENT_MAX_FILES,
  enableImageCrop = false,
  onImagePreview,
}) => {
  const { t } = useLocale();
  const inputId = useId();
  const inputRef = useRef<HTMLInputElement>(null);
  const [dragActive, setDragActive] = useState(false);
  const [validationError, setValidationError] = useState<string | null>(null);
  const [cropFile, setCropFile] = useState<File | null>(null);
  const [pendingQueue, setPendingQueue] = useState<File[]>([]);

  const commitFiles = useCallback(
    (incoming: File[]) => {
      const merged = [...files, ...incoming].slice(0, maxFiles);
      const err = validateAttachmentFiles(merged);
      setValidationError(err);
      if (!err) {
        onFilesChange(merged);
      }
    },
    [files, maxFiles, onFilesChange],
  );

  const processQueue = useCallback(
    (queue: File[]) => {
      if (queue.length === 0) return;

      let index = 0;
      const batch: File[] = [];
      while (
        index < queue.length &&
        !(enableImageCrop && isPreviewableImage(queue[index]))
      ) {
        batch.push(queue[index]);
        index += 1;
      }

      if (batch.length > 0) {
        commitFiles(batch);
      }

      if (index < queue.length) {
        setPendingQueue(queue.slice(index + 1));
        setCropFile(queue[index]);
      }
    },
    [commitFiles, enableImageCrop],
  );

  const applyFiles = useCallback(
    (incoming: File[]) => {
      if (incoming.length === 0) return;
      processQueue(incoming);
    },
    [processQueue],
  );

  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const list = Array.from(event.target.files ?? []);
    applyFiles(list);
    event.target.value = '';
  };

  const onDragEnter = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (!disabled) setDragActive(true);
  };

  const onDragLeave = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragActive(false);
  };

  const onDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragActive(false);
    if (disabled) return;
    applyFiles(Array.from(e.dataTransfer.files ?? []));
  };

  const displayError = externalError ?? validationError;
  const extensions = ATTACHMENT_ALLOWED_EXTENSIONS.join(', ');

  return (
    <div>
      <Zone
        $active={dragActive}
        $hasError={!!displayError}
        onDragEnter={onDragEnter}
        onDragOver={(e) => e.preventDefault()}
        onDragLeave={onDragLeave}
        onDrop={onDrop}
        onClick={() => !disabled && inputRef.current?.click()}
        onKeyDown={(e) => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            inputRef.current?.click();
          }
        }}
        role="button"
        tabIndex={disabled ? -1 : 0}
        aria-disabled={disabled}
        aria-describedby={displayError ? `${inputId}-error` : undefined}
      >
        <HiddenInput
          ref={inputRef}
          id={inputId}
          type="file"
          multiple
          disabled={disabled}
          accept={ATTACHMENT_ALLOWED_EXTENSIONS.map((e) => `.${e}`).join(',')}
          onChange={handleInputChange}
        />
        <IconWrap aria-hidden>
          <HiCloudUpload />
        </IconWrap>
        <Title>{t('tickets:upload.dropTitle')}</Title>
        <Hint>
          {t('tickets:upload.dropHint', { max: maxFiles, extensions })}
        </Hint>
      </Zone>
      {displayError && (
        <ErrorText id={`${inputId}-error`} role="alert">
          {displayError}
        </ErrorText>
      )}
      <FilePreviewList
        files={files}
        onRemove={(index) => {
          const next = files.filter((_, i) => i !== index);
          setValidationError(validateAttachmentFiles(next));
          onFilesChange(next);
        }}
        onPreviewImage={onImagePreview}
      />

      {enableImageCrop && (
        <ImageCropModal
          isOpen={Boolean(cropFile)}
          file={cropFile}
          onClose={() => {
            setCropFile(null);
            setPendingQueue([]);
          }}
          onConfirm={(processed) => {
            commitFiles([processed]);
            setCropFile(null);
            const rest = pendingQueue;
            setPendingQueue([]);
            if (rest.length > 0) {
              processQueue(rest);
            }
          }}
          maxDimension={1280}
          title={t('tickets:upload.cropTitle')}
        />
      )}
    </div>
  );
};
