import { useCallback, useEffect, useRef, useState } from 'react';
import { Save } from 'lucide-react';
import { Button, Dialog, Input, Select, Spinner } from '../../components';
import {
  createSmartCollection,
  getSmartCollections,
  messageFromCollectionError,
  updateSmartCollection,
  type SmartCollection
} from '../../api';

export interface SaveAsSmartCollectionDialogProps {
  open: boolean;
  onClose: () => void;
  // The search query the saved smart collection will store.
  query: string;
  onSaved?: (collectionName: string) => void;
}

const NEW_COLLECTION = '__new__';

export function SaveAsSmartCollectionDialog(props: SaveAsSmartCollectionDialogProps) {
  if (!props.open) {
    return null;
  }

  return <SaveAsSmartCollectionDialogBody {...props} />;
}

function SaveAsSmartCollectionDialogBody({ onClose, query, onSaved }: SaveAsSmartCollectionDialogProps) {
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [collections, setCollections] = useState<SmartCollection[]>([]);
  const [selected, setSelected] = useState<string>(NEW_COLLECTION);
  const [newName, setNewName] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const activeRef = useRef(true);

  useEffect(() => {
    activeRef.current = true;

    return () => {
      activeRef.current = false;
    };
  }, []);

  const load = useCallback(() => {
    getSmartCollections()
      .then((result) => {
        if (!activeRef.current) {
          return;
        }

        setCollections(result);
        setSelected(NEW_COLLECTION);
        setLoadError(null);
        setLoading(false);
      })
      .catch((error: unknown) => {
        if (!activeRef.current) {
          return;
        }

        setLoadError(messageFromCollectionError(error, 'Unable to load smart collections'));
        setLoading(false);
      });
  }, []);

  useEffect(() => {
    load();
  }, [load]);

  const isNew = selected === NEW_COLLECTION;
  const canSubmit = !submitting && (!isNew || newName.trim().length > 0);

  const submit = () => {
    if (!canSubmit) {
      return;
    }

    setSubmitting(true);
    setSubmitError(null);

    // New: create with the query baked in. Existing: overwrite its query (keeping its name).
    const save: Promise<string> = isNew
      ? createSmartCollection({ name: newName.trim(), query }).then(
          (collection) => collection.name ?? newName.trim()
        )
      : (() => {
          const existing = collections.find((collection) => String(collection.id) === selected);
          const name = existing?.name ?? 'smart collection';
          return updateSmartCollection(Number(selected), { name, query }).then(() => name);
        })();

    save
      .then((name) => {
        if (!activeRef.current) {
          return;
        }

        onSaved?.(name);
        onClose();
      })
      .catch((error: unknown) => {
        if (!activeRef.current) {
          return;
        }

        setSubmitError(messageFromCollectionError(error, 'Unable to save smart collection'));
        setSubmitting(false);
      });
  };

  const options = [
    { value: NEW_COLLECTION, label: '(New smart collection)' },
    ...collections.map((collection) => ({
      value: String(collection.id),
      label: collection.name ?? `Smart collection ${collection.id}`
    }))
  ];

  return (
    <Dialog
      footer={
        <>
          <Button disabled={submitting} onClick={onClose} variant="secondary">
            Cancel
          </Button>
          <Button
            disabled={!canSubmit}
            loading={submitting}
            onClick={submit}
            startIcon={<Save aria-hidden="true" size={14} />}
            variant="primary"
          >
            Save as smart collection
          </Button>
        </>
      }
      onClose={onClose}
      open
      title="Save as smart collection"
      width={460}
    >
      {loading ? (
        <div style={{ display: 'flex', justifyContent: 'center', padding: 24 }}>
          <Spinner />
        </div>
      ) : loadError ? (
        <span className="ctv-field-error" role="alert">
          {loadError}
        </span>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <Select
            label="Smart collection"
            onChange={(event) => setSelected(event.target.value)}
            options={options}
            value={selected}
          />
          {isNew && (
            <Input
              label="New smart collection name"
              onChange={(event) => setNewName(event.target.value)}
              placeholder="Smart collection name"
              value={newName}
            />
          )}
          {submitError && (
            <span className="ctv-field-error" role="alert">
              {submitError}
            </span>
          )}
        </div>
      )}
    </Dialog>
  );
}
