'use client';

import React, { useRef, useEffect, useMemo } from 'react';
import { ControllerRenderProps, FieldValues } from 'react-hook-form';
import Image from 'next/image';
import CommonImage from '@/components/common/CommonImage';
import { useAppToast } from '@/hooks/useAppToast';

type FileUploadFieldProps = {
  field: ControllerRenderProps<FieldValues, string>;
  label: string;
  acceptFileFormat?: string;
  maxFiles?: number;
  maxFileSize?: number;
  acceptFileFormatLabel?: string;
  files: File[];
  onFilesChange: (files: File[]) => void;
  dropdownOpen: boolean;
  onToggleDropdown: () => void;
  onRemoveFile: (index: number) => void;
  className?: string;
};

export const FileUploadField: React.FC<FileUploadFieldProps> = React.memo(
  ({
    field,
    label,
    acceptFileFormat = 'image/*',
    maxFiles = 5,
    maxFileSize = 10,
    acceptFileFormatLabel = 'jpg,png,jpeg,pdf,webp',
    files,
    onFilesChange,
    dropdownOpen,
    onToggleDropdown,
    onRemoveFile,
    className = 'w-full md:w-1/2 lg:w-1/2',
  }) => {
    const inputRef = useRef<HTMLInputElement>(null);
    const { showError } = useAppToast();

    const imageExt = useMemo(
      () =>
        new Set(['jpg', 'jpeg', 'png', 'webp', 'JPG', 'JPEG', 'PNG', 'WEBP']),
      [],
    );
    const excelExt = useMemo(() => new Set(['xls', 'xlsx', 'XLS', 'XLSX']), []);
    const wordExt = useMemo(() => new Set(['doc', 'docx', 'DOC', 'DOCX']), []);

    const previews = useMemo(() => {
      return files.map((file) => {
        const ext = file.name.split('.').pop()?.toLowerCase() || '';

        if (imageExt.has(ext)) {
          return {
            type: 'image',
            url: URL.createObjectURL(file),
          };
        }

        if (['pdf', 'PDF'].includes(ext || ''))
          return { type: 'icon', url: '/main/pdf-icon.webp' };
        if (excelExt.has(ext))
          return { type: 'icon', url: '/main/excel-icon.webp' };
        if (wordExt.has(ext))
          return { type: 'icon', url: '/main/word-icon.webp' };

        return { type: 'icon', url: '/main/file-icon.webp' };
      });
    }, [files, imageExt, excelExt, wordExt]);

    useEffect(() => {
      return () => {
        previews.forEach((p) => {
          if (p.type === 'image') {
            URL.revokeObjectURL(p.url);
          }
        });
      };
    }, [previews]);

    const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      const newFiles = Array.from(e.target.files || []);
      const MAX_SIZE = maxFileSize * 1024 * 1024 * 1024 * 1024;

      const validFiles: File[] = [];

      for (const file of newFiles) {
        const ext = file.name.split('.').pop()?.toLowerCase();

        if (!ext || !acceptFileFormat.includes(ext)) {
          showError(`Allowed file type only: ${acceptFileFormatLabel}`, '');
          continue;
        }

        if (file.size > MAX_SIZE) {
          showError(`Maximum allowed file size: ${maxFileSize} MB`, '');
          continue;
        }

        validFiles.push(file);
      }

      let updatedFiles = [...files, ...validFiles];

      if (updatedFiles.length > maxFiles) {
        showError(`Maximum ${maxFiles} files allowed`, '');
        updatedFiles = updatedFiles.slice(0, maxFiles);
      }

      onFilesChange(updatedFiles);
      field.onChange(updatedFiles);

      if (inputRef.current) inputRef.current.value = '';
    };

    return (
      <div className={`relative p-2 multiple-select-file ${className}`}>
        <label className="block font-bold mb-2 text-sm">{label}</label>

        <div className="flex relative gap-4">
          <input
            ref={inputRef}
            type="file"
            multiple
            accept={acceptFileFormat}
            onChange={handleFileChange}
            className="hidden"
          />

          <button
            type="button"
            onClick={() => inputRef.current?.click()}
            className="border border-gray-900 px-3 py-1 rounded bg-white hover:bg-gray-100 w-full"
          >
            Upload Files
          </button>

          {files.length > 0 && (
            <span className="hide-show-widget">
              <button
                type="button"
                onClick={onToggleDropdown}
                className="btn-hide bg-gray-200 rounded hover:bg-gray-300"
              >
                {dropdownOpen ? 'Hide' : 'Show'}
              </button>

              {dropdownOpen && (
                <div className="uploadedFiles-widget flex flex-wrap shadow-md outline-none">
                  {files.map((file, index) => {
                    const preview = previews[index];

                    return (
                      <div key={index} className="uploadedFiles-cont">
                        <div className="w-full">
                          <Image
                            src={preview.url}
                            alt={`Preview ${index}`}
                            width={200}
                            height={160}
                            className="max-h-40 object-contain mb-2 rounded border"
                            title={`${file.name} - ${(file.size / 1024).toFixed(
                              2,
                            )}KB - ${file.type}`}
                            unoptimized
                          />
                        </div>

                        <button
                          type="button"
                          onClick={() => {
                            onRemoveFile(index);
                            if (inputRef.current) {
                              inputRef.current.value = '';
                            }
                          }}
                          className="text-red-600 font-semibold remove-image"
                        >
                          <CommonImage
                            src="/main/cross-arrow.webp"
                            width={14}
                            height={14}
                            alt="Close"
                            classname="cross-icon"
                          />
                        </button>
                      </div>
                    );
                  })}
                </div>
              )}
            </span>
          )}
        </div>
      </div>
    );
  },
);

FileUploadField.displayName = 'FileUploadField';
