import { useEffect, useState } from 'react';

import { handleRequestError } from '@grafana/api-clients';
import {
  type Correlation as CorrelationK8s,
  useListCorrelationQuery,
} from '@grafana/api-clients/rtkq/correlations/v0alpha1';
import { SupportedTransformationType } from '@grafana/data';
import { type CorrelationData, type CorrelationExternal, type CorrelationQuery } from '@grafana/runtime';
import { getDataSourceInstanceSettings } from '@grafana/runtime/unstable';

import { toEnrichedCorrelationData } from './useCorrelations';

export const toEnrichedCorrelationDataK8s = async (item: CorrelationK8s): Promise<CorrelationData | undefined> => {
  const sourceDS = await getDataSourceInstanceSettings({ type: item.spec.source.group, uid: item.spec.source.name });
  if (sourceDS !== undefined) {
    // if a resource has a manager set, it must explicitly allow edits
    const isManaged = item.metadata.annotations?.['grafana.app/managedBy'] !== undefined;
    const managerAllowsEdits = item.metadata.annotations?.['grafana.app/managerAllowsEdits'] === 'true';
    const managedReadOnly = isManaged && !managerAllowsEdits;

    const baseCor = {
      uid: item.metadata.name!,
      sourceUID: sourceDS.uid,
      label: item.spec.label,
      description: item.spec.description,
      provisioned: managedReadOnly,
    };

    const transformationsFmt = item.spec.config.transformations?.map((trans) => {
      return {
        ...trans,
        type: trans.type === 'regex' ? SupportedTransformationType.Regex : SupportedTransformationType.Logfmt,
      };
    });

    if (item.spec.type === 'external') {
      const extCorr: CorrelationExternal = {
        ...baseCor,
        type: 'external',
        config: {
          field: item.spec.config.field,
          target: {
            url: item.spec.config?.target?.url || '',
          },
          transformations: transformationsFmt,
        },
      };
      return toEnrichedCorrelationData(extCorr);
    } else {
      const targetDs = await getDataSourceInstanceSettings({
        type: item.spec.target?.group,
        uid: item.spec.target?.name,
      });
      if (targetDs !== undefined) {
        const queryCorr: CorrelationQuery = {
          ...baseCor,
          type: 'query',
          targetUID: targetDs.uid,
          config: {
            field: item.spec.config.field,
            target: item.spec.config.target,
            transformations: transformationsFmt,
          },
        };

        return toEnrichedCorrelationData(queryCorr);
      } else {
        return undefined;
      }
    }
  } else {
    return undefined;
  }
};

// we're faking traditional pagination here, realistically folks shouldnt have enough correlations to see a performance impact but if they do we can change the ui
export const useCorrelationsK8s = (limit = 100, page: number) => {
  let pagedLimit = limit;
  if (page > 1) {
    pagedLimit = limit * page;
  }

  const { currentData, isLoading, error } = useListCorrelationQuery({ limit: pagedLimit });

  const [enrichedCorrelations, setEnrichedCorrelations] = useState<CorrelationData[]>([]);
  const [isEnriching, setIsEnriching] = useState(false);

  useEffect(() => {
    if (currentData === undefined) {
      setEnrichedCorrelations([]);
      return;
    }

    let cancelled = false;
    setIsEnriching(true);

    const startIdx = limit * (page - 1);
    const pagedData = currentData.items.slice(startIdx, startIdx + limit);

    Promise.all(
      pagedData.filter((i) => i.metadata.name !== undefined).map((item) => toEnrichedCorrelationDataK8s(item))
    ).then((enriched) => {
      if (!cancelled) {
        setEnrichedCorrelations(enriched.filter((i) => i !== undefined));
        setIsEnriching(false);
      }
    });

    return () => {
      cancelled = true;
    };
  }, [currentData, limit, page]);

  const fmtedError = error ? handleRequestError(error) : undefined;

  return {
    currentData: enrichedCorrelations,
    isLoading: isLoading || isEnriching,
    error: fmtedError,
    remainingItems: currentData?.metadata.remainingItemCount || 0,
    doesContinue: currentData?.metadata.continue !== undefined,
  };
};
