/**
 * This Source Code is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) Infonomic Company Limited
 */
import { useCallback, useEffect, useState } from 'react';
import { getCollectionAdminConfig } from '@byline/core';
import { useTranslation } from '@byline/i18n/react';
import { Button, CheckIcon, LoaderRing, Modal, Search } from '@byline/ui/react';
import cx from 'clsx';
import { useBylineFieldServices } from '../field-services-context';
import { PickerCell, resolveFallbackDisplayField, resolveRowLabel, resolveSelectFields, } from './relation-display';
import styles from './relation-picker.module.css';
const PAGE_SIZE = 15;
export const RelationPicker = ({ targetCollectionPath, targetDefinition, displayField, extraSelectFields, isOpen, multiple = false, excludeIds, onSelect, onSelectMany, onDismiss, }) => {
    const [query, setQuery] = useState('');
    const [page, setPage] = useState(1);
    const { t } = useTranslation('byline-admin');
    const [selectedDocumentId, setSelectedDocumentId] = useState(null);
    // Multi-select state. A Map keyed by target id preserves pick order (the
    // confirmed batch appends in that order) and carries each row's record so
    // picks survive page/search changes that swap out `documents`.
    const [selectedMap, setSelectedMap] = useState(() => new Map());
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [documents, setDocuments] = useState([]);
    const [totalPages, setTotalPages] = useState(1);
    const [collectionId, setCollectionId] = useState(null);
    const { getCollectionDocuments } = useBylineFieldServices();
    const targetAdminConfig = getCollectionAdminConfig(targetCollectionPath);
    const pickerColumns = targetAdminConfig?.itemView;
    // Reset local state each time the modal opens so prior queries don't leak.
    useEffect(() => {
        if (isOpen) {
            setQuery('');
            setPage(1);
            setSelectedDocumentId(null);
            setSelectedMap(new Map());
            setError(null);
        }
    }, [isOpen]);
    // Fetch whenever the modal is open and the query / page changes.
    useEffect(() => {
        if (!isOpen)
            return;
        let cancelled = false;
        const selectFields = resolveSelectFields(targetDefinition, displayField, pickerColumns, extraSelectFields);
        setLoading(true);
        setError(null);
        // Item-view sort: the target collection's `itemViewSort` (boot-validated)
        // orders the picker independently of its list view's `defaultSort`.
        // Passed as explicit params because the list server fn gives an explicit
        // `order` top precedence; when absent the server falls back through
        // `defaultSort` → `created_at desc` (or `order_key asc` for orderable
        // collections) exactly as before.
        const itemViewSort = targetAdminConfig?.itemViewSort;
        getCollectionDocuments({
            collection: targetCollectionPath,
            params: {
                page,
                page_size: PAGE_SIZE,
                query: query.length > 0 ? query : undefined,
                fields: selectFields,
                ...(itemViewSort != null
                    ? { order: String(itemViewSort.field), desc: itemViewSort.direction === 'desc' }
                    : {}),
            },
        })
            .then((response) => {
            if (cancelled)
                return;
            setDocuments(response.docs);
            setTotalPages(response.meta.totalPages ?? 1);
            setCollectionId(response.included.collection.id);
        })
            .catch((err) => {
            if (cancelled)
                return;
            setError(err instanceof Error ? err.message : t('fields.relation.picker.loadFailed'));
        })
            .finally(() => {
            if (!cancelled)
                setLoading(false);
        });
        return () => {
            cancelled = true;
        };
    }, [
        isOpen,
        targetCollectionPath,
        query,
        page,
        displayField,
        extraSelectFields,
        targetDefinition,
        pickerColumns,
        getCollectionDocuments,
        t,
        targetAdminConfig?.itemViewSort,
    ]);
    const resolvedDisplayField = displayField ??
        targetDefinition?.useAsTitle ??
        resolveFallbackDisplayField(targetDefinition) ??
        null;
    const handleSelect = useCallback(() => {
        if (!selectedDocumentId || !collectionId || !onSelect)
            return;
        const record = documents.find((d) => d?.id === selectedDocumentId);
        onSelect({
            targetDocumentId: selectedDocumentId,
            targetCollectionId: collectionId,
            record,
        });
    }, [selectedDocumentId, collectionId, documents, onSelect]);
    const handleSelectMany = useCallback(() => {
        if (selectedMap.size === 0 || !collectionId || !onSelectMany)
            return;
        onSelectMany(Array.from(selectedMap, ([targetDocumentId, record]) => ({
            targetDocumentId,
            targetCollectionId: collectionId,
            record,
        })));
    }, [selectedMap, collectionId, onSelectMany]);
    const toggleSelected = useCallback((doc) => {
        const id = doc.id;
        setSelectedMap((prev) => {
            const next = new Map(prev);
            if (next.has(id)) {
                next.delete(id);
            }
            else {
                next.set(id, doc);
            }
            return next;
        });
    }, []);
    const title = t('fields.relation.selectPickerTitle', {
        label: targetDefinition?.labels.singular ?? targetCollectionPath,
    });
    return (<Modal isOpen={isOpen} onDismiss={onDismiss}>
      <Modal.Container style={{ maxWidth: '600px', width: '100%' }}>
        <Modal.Header className={cx('byline-field-relation-picker-header', styles.header)}>
          <h3 className={cx('byline-field-relation-picker-title', styles.title)}>{title}</h3>
        </Modal.Header>
        <Modal.Content>
          <div className={cx('byline-field-relation-picker-body', styles.body)}>
            <Search onSearch={(q) => {
            setPage(1);
            setQuery(q ?? '');
        }} onClear={() => {
            setPage(1);
            setQuery('');
        }} inputSize="sm" placeholder={t('fields.relation.picker.searchPlaceholder')}/>

            <div className={cx('byline-field-relation-picker-list', styles.list)}>
              {loading && documents.length === 0 && (<div className={cx('byline-field-relation-picker-loading', styles.loading)}>
                  <LoaderRing size={24} color="#888888"/>
                </div>)}
              {!loading && error && (<div className={cx('byline-field-relation-picker-error', styles.error)}>
                  {error}
                </div>)}
              {!loading && !error && documents.length === 0 && (<div className={cx('byline-field-relation-picker-empty', styles.empty)}>
                  {t('fields.relation.picker.empty')}
                </div>)}
              {documents.length > 0 && (<ul className={cx('byline-field-relation-picker-rows', styles.rows)}>
                  {documents.map((doc) => {
                const id = doc.id;
                const selected = multiple ? selectedMap.has(id) : selectedDocumentId === id;
                const excluded = multiple && (excludeIds?.includes(id) ?? false);
                return (<li key={id}>
                        <button type="button" disabled={excluded} aria-pressed={multiple ? selected : undefined} title={excluded ? t('fields.relation.picker.alreadyAdded') : undefined} className={cx('byline-field-relation-picker-row-button', styles['row-button'], multiple && [
                        'byline-field-relation-picker-row-multi',
                        styles['row-multi'],
                    ], selected && [
                        'byline-field-relation-picker-row-selected',
                        styles['row-selected'],
                    ], excluded && [
                        'byline-field-relation-picker-row-added',
                        styles['row-added'],
                    ])} onClick={() => {
                        if (excluded)
                            return;
                        if (multiple) {
                            toggleSelected(doc);
                        }
                        else {
                            setSelectedDocumentId(id);
                        }
                    }}>
                          {multiple && (<span aria-hidden="true" className={cx('byline-field-relation-picker-check', styles.check, (selected || excluded) && [
                            'byline-field-relation-picker-check-checked',
                            styles['check-checked'],
                        ])}>
                              {(selected || excluded) && <CheckIcon width="12px" height="12px"/>}
                            </span>)}
                          {pickerColumns && pickerColumns.length > 0 ? (<div className={cx('byline-field-relation-picker-row-cells', styles['row-cells'])}>
                              {pickerColumns.map((col) => (<PickerCell key={String(col.fieldName)} column={col} record={doc}/>))}
                            </div>) : (<div className={cx('byline-field-relation-picker-row-stack', styles['row-stack'])}>
                              <span className={cx('byline-field-relation-picker-row-label', styles['row-label'])}>
                                {resolveRowLabel(doc, resolvedDisplayField) || id}
                              </span>
                              {typeof doc.path === 'string' && doc.path.length > 0 && (<span className={cx('byline-field-relation-picker-row-path', styles['row-path'])}>
                                  {doc.path}
                                </span>)}
                            </div>)}
                          {excluded && (<span className={cx('byline-field-relation-picker-added-hint', styles['added-hint'])}>
                              {t('fields.relation.picker.alreadyAdded')}
                            </span>)}
                        </button>
                      </li>);
            })}
                </ul>)}
            </div>

            {totalPages > 1 && (<div className={cx('byline-field-relation-picker-pager', styles.pager)}>
                <Button size="xs" variant="outlined" intent="noeffect" type="button" disabled={page <= 1 || loading} onClick={() => setPage((p) => Math.max(1, p - 1))}>
                  {t('common.pager.previous')}
                </Button>
                <span>{t('common.pager.pageOf', { page, total: totalPages })}</span>
                <Button size="xs" variant="outlined" intent="noeffect" type="button" disabled={page >= totalPages || loading} onClick={() => setPage((p) => Math.min(totalPages, p + 1))}>
                  {t('common.pager.next')}
                </Button>
              </div>)}
          </div>
        </Modal.Content>
        <Modal.Actions>
          <Button size="sm" intent="noeffect" type="button" onClick={onDismiss} className={cx('byline-field-relation-picker-action', styles.action)}>
            {t('common.actions.cancel')}
          </Button>
          <Button size="sm" className={cx('byline-field-relation-picker-action', styles.action)} intent="primary" type="button" disabled={multiple ? selectedMap.size === 0 : !selectedDocumentId} onClick={multiple ? handleSelectMany : handleSelect}>
            {multiple
            ? t('fields.relation.picker.addSelected', { count: selectedMap.size })
            : t('common.actions.select')}
          </Button>
        </Modal.Actions>
      </Modal.Container>
    </Modal>);
};
