import React, { useEffect, useMemo, useState } from 'react';
import { observer } from 'mobx-react-lite';
import { sourceFetchData } from '@wix/bex-core';
import type { BaseReferenceField, Field, Schema } from '@wix/bex-core';
import type { Control } from '@wix/bex-core/form';
import { useCollection } from '@wix/bex-core/react';
import { FormReference, FormMultiReference } from '@wix/patterns-fields';
import { useEntityPageContext } from '../../providers';

type RefRow = Record<string, unknown>;

const imageFieldOf = (
  fields: Schema['fields'] | undefined,
): string | undefined =>
  Object.entries(fields ?? {}).find(([, f]) => f?.type === 'IMAGE')?.[0];

export interface EntityPageReferenceFieldProps {
  field: Field;
  formControl: Control<any>;
  data: Record<string, unknown>;
}

// Adapts a referenced SchemaSource (schemaSource.references[collectionId]) to the
// data-agnostic FormReference / FormMultiReference renderers: it queries the
// referenced collection for candidate items and derives the referenced schema's
// id/display/image fields, mirroring EditableTable's reference cell Edit.
function _EntityPageReferenceField({
  field,
  formControl,
  data,
}: EntityPageReferenceFieldProps) {
  const state = useEntityPageContext();
  const referencedCollectionId = (field as BaseReferenceField).referenceMetadata
    ?.referencedCollectionId;
  const refSource = referencedCollectionId
    ? state.schemaSource?.references?.[referencedCollectionId]
    : undefined;

  const collection = useCollection<RefRow>(
    refSource
      ? {
          queryName: `entity-page-reference-${refSource.collectionId}`,
          paginationMode: refSource.paginationMode,
          fetchData: sourceFetchData(refSource),
          itemKey: refSource.itemKey,
          itemName: refSource.itemName,
        }
      : {
          queryName: `entity-page-reference-${field.id}`,
          paginationMode: 'offset',
          fetchData: async () => ({ items: [], total: 0 }),
          itemKey: (row: RefRow) => String(row.id ?? ''),
          itemName: (row: RefRow) => String(row.id ?? ''),
        },
  );

  useEffect(() => collection.init(), [collection]);

  const [refSchema, setRefSchema] = useState<Schema | null>(null);
  useEffect(() => {
    let active = true;
    refSource?.loadSchema().then((loaded) => {
      if (active) {
        setRefSchema(loaded.schema);
      }
    });
    return () => {
      active = false;
    };
  }, [refSource]);

  const idField = refSchema?.idField;
  const displayField = refSchema?.displayField;
  const imageField = imageFieldOf(refSchema?.fields);

  const items = useMemo(() => {
    if (!idField || !displayField) {
      return [];
    }
    return collection.result.keyedItems.map((ki) => ({
      id: String((ki.item as RefRow)[idField] ?? ki.key),
      name: String((ki.item as RefRow)[displayField] ?? ''),
      image: imageField
        ? ((ki.item as RefRow)[imageField] as string | undefined)
        : undefined,
    }));
  }, [collection.result.keyedItems, idField, displayField, imageField]);

  // A reference with no matching source entry, or before its schema resolves,
  // can't render a picker — skip it rather than render a broken input.
  if (!refSource || !idField || !displayField) {
    return null;
  }

  const shared = {
    field,
    value: data?.[field.id] as never,
    onChange: () => {},
    formControl,
    data,
    dataHook: `entity-page-field-${field.id}`,
    items,
    idField,
    displayField,
    imageField,
    searchValue: collection.query.search.value,
    onSearch: (query: string) => collection.search(query),
    onClearSearch: () => collection.clearSearch(),
    hasMore: !collection.fetchedLastPage,
    loadMore: collection.fetchNextPageIfNeeded,
  };

  return field.type === 'MULTI_REFERENCE' ? (
    <FormMultiReference {...shared} />
  ) : (
    <FormReference {...shared} />
  );
}

export const EntityPageReferenceField = observer(_EntityPageReferenceField);
