import React, { ReactElement, useEffect, useMemo, useState } from 'react';

import { requestJson } from '../../utils';

type CategoryItem = {
  term_id: string | number;
  parent?: string | number;
  name?: string;
  path?: string;
  count?: string | number;
};

type CategoryNode = {
  item: CategoryItem;
  children: CategoryNode[];
};

type FileItem = {
  id: string | number;
  term_id: string | number;
  name?: string;
  title?: string;
  ext?: string;
  size?: string;
  created?: string;
  categoryFrom?: string;
};

const normalizeId = (value: string | number | undefined): string => String(value ?? '');
const normalizeParentId = (value: string | number | undefined): string => {
  const parent = String(value ?? '0');
  return parent === '' ? '0' : parent;
};

const buildTree = (categories: CategoryItem[]): CategoryNode[] => {
  const nodeMap = new Map<string, CategoryNode>();
  const roots: CategoryNode[] = [];

  categories.forEach((item) => {
    nodeMap.set(normalizeId(item.term_id), {
      item,
      children: [],
    });
  });

  categories.forEach((item) => {
    const node = nodeMap.get(normalizeId(item.term_id));
    const parentId = normalizeParentId(item.parent);

    if (!node) {
      return;
    }

    if (parentId !== '0' && nodeMap.has(parentId)) {
      nodeMap.get(parentId)?.children.push(node);
      return;
    }

    roots.push(node);
  });

  return roots;
};

const collectExpandedIds = (nodes: CategoryNode[], expanded: Set<string>) => {
  nodes.forEach((node) => {
    if (node.children.length > 0) {
      expanded.add(normalizeId(node.item.term_id));
      collectExpandedIds(node.children, expanded);
    }
  });
};

const filterTree = (nodes: CategoryNode[], query: string): CategoryNode[] => {
  const normalizedQuery = query.trim().toLowerCase();

  if (!normalizedQuery) {
    return nodes;
  }

  return nodes.reduce<CategoryNode[]>((acc, node) => {
    const name = String(node.item.name ?? '').toLowerCase();
    const path = String(node.item.path ?? '').toLowerCase();
    const filteredChildren = filterTree(node.children, normalizedQuery);

    if (name.includes(normalizedQuery) || path.includes(normalizedQuery) || filteredChildren.length > 0) {
      acc.push({
        item: node.item,
        children: filteredChildren,
      });
    }

    return acc;
  }, []);
};

const FolderIcon = ({ color = '#afb8d4' }: { color?: string }): ReactElement => (
  <svg
    aria-hidden="true"
    width="16"
    height="16"
    viewBox="0 0 18 18"
    style={{ display: 'block' }}
  >
    <path
      d="M2 4.75h4.1l1.15 1.35H16c.55 0 1 .45 1 1v6.9c0 .55-.45 1-1 1H2c-.55 0-1-.45-1-1v-8.25c0-.55.45-1 1-1Z"
      fill={color}
    />
    <path
      d="M1.9 6.15h14.2c.5 0 .9.4.9.9v.25H1v-.25c0-.5.4-.9.9-.9Z"
      fill="rgba(255,255,255,0.24)"
    />
  </svg>
);

const getFileLabel = (file: FileItem): string => String(file.title || file.name || file.id || '');

const getFileId = (file: FileItem): string =>
  file.categoryFrom === 'aws' ? decodeURIComponent(String(file.id ?? '')) : String(file.id ?? '');

type CategoryTreeNodeProps = {
  currentCategoryId: string;
  depth?: number;
  expandedIds: Set<string>;
  readonly?: boolean;
  onSelect: (item: CategoryItem) => void;
  onToggle: (id: string) => void;
  node: CategoryNode;
};

const CategoryTreeNode = ({
  currentCategoryId,
  depth = 0,
  expandedIds,
  readonly,
  onSelect,
  onToggle,
  node,
}: CategoryTreeNodeProps): ReactElement => {
  const nodeId = normalizeId(node.item.term_id);
  const hasChildren = node.children.length > 0;
  const isExpanded = expandedIds.has(nodeId);
  const isActive = currentCategoryId === nodeId;

  return (
    <div>
      <button
        type="button"
        disabled={readonly}
        onClick={() => onSelect(node.item)}
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 8,
          width: '100%',
          textAlign: 'left',
          padding: '5px 8px',
          paddingLeft: `${8 + (depth * 16)}px`,
          border: 'none',
          background: isActive ? '#eef4ff' : 'transparent',
          borderRadius: 4,
          cursor: readonly ? 'default' : 'pointer',
          color: '#1d2327',
        }}
      >
        <span
          onClick={(event) => {
            if (!hasChildren) {
              return;
            }

            event.preventDefault();
            event.stopPropagation();
            onToggle(nodeId);
          }}
          style={{
            width: 12,
            color: hasChildren ? '#50575e' : 'transparent',
            cursor: hasChildren && !readonly ? 'pointer' : 'default',
            userSelect: 'none',
            flexShrink: 0,
            fontSize: 10,
          }}
        >
          {hasChildren ? (isExpanded ? '▼' : '▶') : '•'}
        </span>
        <span style={{ flexShrink: 0, display: 'inline-flex', alignItems: 'center' }}>
          <FolderIcon color={isActive ? '#8aa9e6' : '#afb8d4'} />
        </span>
        <span style={{ fontWeight: isActive ? 600 : 400, lineHeight: 1.3 }}>
          {node.item.name || node.item.term_id}
        </span>
        {typeof node.item.count !== 'undefined' && (
          <span style={{ marginLeft: 'auto', color: '#646970', fontSize: 12 }}>
            ({node.item.count})
          </span>
        )}
      </button>

      {hasChildren && isExpanded && (
        <div>
          {node.children.map((child) => (
            <CategoryTreeNode
              key={normalizeId(child.item.term_id)}
              currentCategoryId={currentCategoryId}
              depth={depth + 1}
              expandedIds={expandedIds}
              readonly={readonly}
              onSelect={onSelect}
              onToggle={onToggle}
              node={child}
            />
          ))}
        </div>
      )}
    </div>
  );
};

export const WpfdFilePickerField = (props: any): ReactElement => {
  const { value, onChange, readonly } = props;
  const [categories, setCategories] = useState<CategoryItem[]>([]);
  const [selectedCategoryId, setSelectedCategoryId] = useState('');
  const [files, setFiles] = useState<FileItem[]>([]);
  const [categoryQuery, setCategoryQuery] = useState('');
  const [fileQuery, setFileQuery] = useState('');
  const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set());
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [isFileLoading, setIsFileLoading] = useState(false);
  const [managerLink, setManagerLink] = useState('');

  const currentValue = useMemo(() => {
    if (value && typeof value === 'object') {
      return value;
    }

    return {
      selectedFileId: '',
      selectedCategoryId: '',
      selectedFileName: '',
      categoryPath: '',
    };
  }, [value]);

  useEffect(() => {
    requestJson({
      action: 'wpfd',
      task: 'categories.listCats',
    }).then((response) => {
      const nextCategories = Array.isArray(response?.data) ? response.data : [];
      setCategories(nextCategories);

      const initialExpanded = new Set<string>();
      collectExpandedIds(buildTree(nextCategories), initialExpanded);
      setExpandedIds(initialExpanded);

      if (currentValue.selectedCategoryId) {
        setSelectedCategoryId(String(currentValue.selectedCategoryId));
      } else if (nextCategories[0]?.term_id) {
        setSelectedCategoryId(String(nextCategories[0].term_id));
      }
    }).catch(() => {
      setCategories([]);
    });
  }, []);

  useEffect(() => {
    requestJson({
      action: 'wpfd',
      task: 'category.editCategoryLink',
    }).then((response) => {
      setManagerLink(String(response?.data ?? ''));
    }).catch(() => {
      setManagerLink('');
    });
  }, []);

  useEffect(() => {
    if (!selectedCategoryId) {
      setFiles([]);
      return;
    }

    setIsFileLoading(true);

    requestJson({
      action: 'wpfd',
      view: 'files',
      format: 'json',
      id_category: String(selectedCategoryId),
    }).then((response) => {
      setFiles(Array.isArray(response?.data) ? response.data : []);
      setIsFileLoading(false);
    }).catch(() => {
      setFiles([]);
      setIsFileLoading(false);
    });
  }, [selectedCategoryId]);

  const tree = useMemo(() => buildTree(categories), [categories]);
  const visibleTree = useMemo(() => filterTree(tree, categoryQuery), [tree, categoryQuery]);
  const selectedCategory = useMemo(
    () => categories.find((item) => normalizeId(item.term_id) === selectedCategoryId),
    [categories, selectedCategoryId]
  );
  const visibleFiles = useMemo(() => {
    const query = fileQuery.trim().toLowerCase();

    if (!query) {
      return files;
    }

    return files.filter((file) => getFileLabel(file).toLowerCase().includes(query));
  }, [files, fileQuery]);
  const selectedFile = useMemo(
    () => files.find((file) => String(getFileId(file)) === String(currentValue.selectedFileId ?? '')),
    [files, currentValue.selectedFileId]
  );

  const toggleNode = (id: string) => {
    if (readonly) {
      return;
    }

    setExpandedIds((current) => {
      const next = new Set(current);

      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }

      return next;
    });
  };

  const selectCategory = (item: CategoryItem) => {
    if (readonly) {
      return;
    }

    setSelectedCategoryId(normalizeId(item.term_id));
  };

  const selectFile = (file: FileItem) => {
    if (readonly) {
      return;
    }

    const category = categories.find((item) => String(item.term_id) === String(file.term_id));

    onChange({
      inputValue: {
        selectedFileId: getFileId(file),
        selectedCategoryId: String(file.term_id),
        selectedFileName: getFileLabel(file),
        categoryPath: String(category?.path ?? ''),
      },
    });

    setIsModalOpen(false);
  };

  return (
    <div style={{ border: '1px solid #dcdcde', borderRadius: 4, padding: 12, background: '#fff' }}>
      <div style={{ marginBottom: 10 }}>
        <div style={{ fontSize: 12, color: '#50575e', marginBottom: 8 }}>
          {currentValue.selectedFileName
            ? `Selected file: ${currentValue.selectedFileName}`
            : 'No file selected'}
        </div>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <button
            type="button"
            disabled={readonly}
            onClick={() => setIsModalOpen(true)}
            style={{
              width: '100%',
              minHeight: 36,
              padding: '8px 12px',
              borderRadius: 4,
              border: '1px solid #2271b1',
              background: readonly ? '#f6f7f7' : '#2271b1',
              color: readonly ? '#50575e' : '#fff',
              cursor: readonly ? 'default' : 'pointer',
              fontWeight: 600,
            }}
          >
            Browse Files
          </button>
        </div>
      </div>

      {currentValue.selectedFileName && (
        <div style={{ border: '1px solid #dcdcde', borderRadius: 4, padding: 10, background: '#fcfcfc' }}>
          <div style={{ fontSize: 13, fontWeight: 600, lineHeight: 1.35, marginBottom: 6 }}>
            {currentValue.selectedFileName}
          </div>
          {currentValue.categoryPath && (
            <div style={{ fontSize: 12, color: '#646970', marginBottom: 4 }}>
              Category: {currentValue.categoryPath}
            </div>
          )}
          {selectedFile?.ext && (
            <div style={{ fontSize: 12, color: '#646970' }}>
              Type: {String(selectedFile.ext).toUpperCase()}
              {selectedFile.size ? ` • Size: ${selectedFile.size}` : ''}
              {selectedFile.created ? ` • Added: ${selectedFile.created}` : ''}
            </div>
          )}
        </div>
      )}

      {managerLink && (
        <div style={{ marginTop: 10, display: 'flex', justifyContent: 'flex-start' }}>
          <a
            href={managerLink}
            target="_blank"
            rel="noreferrer"
            style={{
              color: '#2271b1',
              fontSize: 12,
              fontWeight: 600,
              textDecoration: 'none',
            }}
          >
            Manage Files
          </a>
        </div>
      )}

      {isModalOpen && (
        <div
          style={{
            position: 'fixed',
            inset: 0,
            background: 'rgba(0, 0, 0, 0.45)',
            zIndex: 999999,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            padding: 24,
          }}
        >
          <div
            style={{
              width: 'min(980px, 100%)',
              maxHeight: 'min(720px, calc(100vh - 48px))',
              background: '#fff',
              borderRadius: 8,
              overflow: 'hidden',
              boxShadow: '0 20px 50px rgba(0, 0, 0, 0.25)',
              display: 'flex',
              flexDirection: 'column',
            }}
          >
            <div
              style={{
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'space-between',
                padding: '14px 18px',
                borderBottom: '1px solid #e0e0e0',
                background: '#fff',
              }}
            >
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                <div style={{ fontSize: 16, fontWeight: 600 }}>Choose File</div>
                {managerLink && (
                  <a
                    href={managerLink}
                    target="_blank"
                    rel="noreferrer"
                    style={{
                      color: '#2271b1',
                      fontSize: 12,
                      fontWeight: 600,
                      textDecoration: 'none',
                    }}
                  >
                    Open Manager
                  </a>
                )}
              </div>
              <button
                type="button"
                onClick={() => setIsModalOpen(false)}
                style={{
                  border: 'none',
                  background: 'transparent',
                  fontSize: 20,
                  lineHeight: 1,
                  cursor: 'pointer',
                  color: '#50575e',
                }}
              >
                ×
              </button>
            </div>

            <div
              style={{
                display: 'grid',
                gridTemplateColumns: '320px minmax(0, 1fr)',
                minHeight: 0,
                flex: 1,
              }}
            >
              <div
                style={{
                  borderRight: '1px solid #e0e0e0',
                  padding: 12,
                  overflow: 'hidden',
                  background: '#fbfbfc',
                  display: 'flex',
                  flexDirection: 'column',
                }}
              >
                <div style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', color: '#50575e', marginBottom: 6 }}>
                  Categories
                </div>
                <input
                  type="text"
                  value={categoryQuery}
                  onChange={(event) => setCategoryQuery(event.target.value)}
                  placeholder="Search category..."
                  disabled={readonly}
                  style={{
                    width: '100%',
                    marginBottom: 8,
                    padding: '8px 10px',
                    border: '1px solid #dcdcde',
                    borderRadius: 4,
                    background: '#fff',
                  }}
                />
                <div
                  style={{
                    overflowY: 'auto',
                    minHeight: 0,
                    border: '1px solid #ececec',
                    borderRadius: 4,
                    padding: 6,
                    background: '#fff',
                  }}
                >
                  {visibleTree.map((node) => (
                    <CategoryTreeNode
                      key={normalizeId(node.item.term_id)}
                      currentCategoryId={selectedCategoryId}
                      expandedIds={expandedIds}
                      readonly={readonly}
                      onSelect={selectCategory}
                      onToggle={toggleNode}
                      node={node}
                    />
                  ))}
                </div>
              </div>

              <div
                style={{
                  padding: 16,
                  overflow: 'hidden',
                  display: 'flex',
                  flexDirection: 'column',
                  minHeight: 0,
                }}
              >
                <div style={{ marginBottom: 10 }}>
                  <div style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', color: '#50575e', marginBottom: 6 }}>
                    Files
                  </div>
                  <div style={{ fontSize: 12, color: '#646970', marginBottom: 8 }}>
                    {selectedCategory ? `Current category: ${selectedCategory.path || selectedCategory.name || selectedCategory.term_id}` : 'No category selected'}
                  </div>
                  <input
                    type="text"
                    value={fileQuery}
                    onChange={(event) => setFileQuery(event.target.value)}
                    placeholder="Search file..."
                    disabled={readonly || !selectedCategoryId}
                    style={{
                      width: '100%',
                      padding: '8px 10px',
                      border: '1px solid #dcdcde',
                      borderRadius: 4,
                    }}
                  />
                </div>

                <div style={{ overflowY: 'auto', minHeight: 0 }}>
                  {isFileLoading ? (
                    <div style={{ padding: 16, color: '#646970' }}>Loading files...</div>
                  ) : visibleFiles.length === 0 ? (
                    <div style={{ padding: 16, color: '#646970' }}>
                      {selectedCategoryId ? 'There is no file in this category yet.' : 'Choose a category first.'}
                    </div>
                  ) : (
                    <div style={{ display: 'grid', gap: 10 }}>
                      {visibleFiles.map((file) => {
                        const currentFileId = String(currentValue.selectedFileId ?? '');
                        const fileId = String(getFileId(file));
                        const isActive = currentFileId === fileId;

                        return (
                          <div
                            key={`${file.term_id}-${file.id}`}
                            style={{
                              display: 'grid',
                              gridTemplateColumns: '56px minmax(0, 1fr) auto',
                              gap: 12,
                              alignItems: 'center',
                              border: isActive ? '1px solid #2271b1' : '1px solid #dcdcde',
                              borderRadius: 6,
                              padding: 12,
                              background: isActive ? '#f0f6fc' : '#fff',
                            }}
                          >
                            <div
                              style={{
                                width: 56,
                                height: 56,
                                borderRadius: 6,
                                background: '#eef2f7',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                color: '#44556b',
                                fontSize: 12,
                                fontWeight: 700,
                                textTransform: 'uppercase',
                              }}
                            >
                              {String(file.ext || '?').slice(0, 4)}
                            </div>

                            <div style={{ minWidth: 0 }}>
                              <div style={{ fontSize: 14, fontWeight: 600, color: '#1d2327', marginBottom: 6 }}>
                                {getFileLabel(file)}
                              </div>
                              <div style={{ fontSize: 12, color: '#646970', lineHeight: 1.45 }}>
                                {file.size ? `Size: ${file.size}` : 'Size: -'}
                                {file.created ? ` • Date added: ${file.created}` : ''}
                                {file.ext ? ` • Type: ${String(file.ext).toUpperCase()}` : ''}
                              </div>
                            </div>

                            <button
                              type="button"
                              onClick={() => selectFile(file)}
                              disabled={readonly}
                              style={{
                                minWidth: 120,
                                padding: '9px 12px',
                                borderRadius: 4,
                                border: isActive ? '1px solid #2271b1' : '1px solid #dcdcde',
                                background: isActive ? '#2271b1' : '#fff',
                                color: isActive ? '#fff' : '#2271b1',
                                fontWeight: 600,
                                cursor: readonly ? 'default' : 'pointer',
                              }}
                            >
                              Insert This File
                            </button>
                          </div>
                        );
                      })}
                    </div>
                  )}
                </div>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};
