import { useRef, useState } from 'react';

import type { LookupResult } from './types';

import Box from '~/src/components/Box';
import Button from '~/src/components/Button';
import Card from '~/src/components/Card';
import MultilineTextInput from '~/src/components/MultilineTextInput';
import { useAppToast } from '~/src/components/NextApp/lib/CoreUi';
import Text from '~/src/components/Text';
import { FlexRow } from '../../components/FlexRow';
import { SERVICE_KEYS } from './constants';
import { LookupResultTable } from './LookupResultTable';
import { ServiceCheckboxList } from './ServiceCheckboxList';
import { performBatchLookup, toCsv } from './utils';

export const AdminLookupTool = () => {
  const [spotifyIds, setSpotifyIds] = useState<string[]>([]);
  const [result, setResult] = useState<LookupResult>();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<Error>();
  const [services, setServices] = useState<string[]>(SERVICE_KEYS);
  const [progress, setProgress] = useState(0);
  const [total, setTotal] = useState(0);

  const cancelRef = useRef(false);
  const toast = useAppToast();

  const handleLookup = async () => {
    if (!spotifyIds.length) return;

    setLoading(true);
    setResult(undefined);
    setProgress(0);
    setTotal(spotifyIds.length);
    setError(undefined);

    await performBatchLookup({
      spotifyIds,
      services,
      isCancelled: () => cancelRef.current,
      onBatchDone: (batch) => {
        setResult((result) => [...(result ?? []), ...batch]);
        setProgress((progress) => progress + batch.length);
      },
      onError: setError,
    });

    setLoading(false);
    cancelRef.current = false;
  };

  const handleCancel = () => {
    cancelRef.current = true;
  };

  const toggleService = (service: string, include: boolean) => {
    let includedServices = services;

    if (include) {
      includedServices = [...services, service];
    } else {
      includedServices = services.filter((s) => s !== service);
    }

    setServices(SERVICE_KEYS.filter((s) => includedServices.includes(s)));
  };

  const copyToClipboardAsCsv = async () => {
    if (!result?.length) return;

    const csv = toCsv(result, services);

    await navigator.clipboard.writeText(csv);
    toast({ text: 'Copied as CSV' });
  };

  return (
    <Box padding="2rem">
      <MultilineTextInput
        rows={10}
        placeholder="Enter Spotify IDs"
        noWrap
        onChange={(e) => {
          e.value
            ? setSpotifyIds(
                e.value
                  .split('\n')
                  .map((line) => line.trim())
                  .filter(Boolean)
              )
            : setSpotifyIds([]);
        }}
      />

      <ServiceCheckboxList onServiceChecked={toggleService} />

      <FlexRow>
        <Button
          isLoading={loading}
          width="auto"
          onClick={() => handleLookup()}
          text="Lookup"
        />
        <Button
          isDisabled={!loading}
          width="auto"
          onClick={() => handleCancel()}
          text="Cancel"
        />
      </FlexRow>

      {error && (
        <Card margin="1rem 0" padding="1.5rem" style={{ color: 'red' }}>
          {error.message}
        </Card>
      )}

      <FlexRow align="flex-end" justify="space-between" margin="1rem 0">
        <FlexRow>
          <Text>
            {progress} / {total}
          </Text>
          {!error && progress === total && result && (
            <span style={{ color: 'green' }}>DONE</span>
          )}
          {error && <span style={{ color: 'red' }}>ERROR</span>}
        </FlexRow>
        <Button
          width="auto"
          isDisabled={!result?.length}
          onClick={() => copyToClipboardAsCsv()}
          text="Copy as CSV"
        />
      </FlexRow>

      <LookupResultTable result={result} services={services} />
    </Box>
  );
};
