import { useQuery } from '@tanstack/react-query';
import { api } from '../client';
import { config as appConfig } from '../../config';
import { useAuthStore } from '../../auth/auth-store';
import { useEnvironmentStore } from '../environment-store';
import type { components } from '../schema';
import type { SearchRequest } from '../types';
import { useLiveQuery } from './use-refresh-interval';

type ExecutionStats = components['schemas']['ExecutionStats'];
type StatsTimeseries = components['schemas']['StatsTimeseries'];
type SearchResultSummary = components['schemas']['SearchResultExecutionSummary'];

// Raw authenticated fetch — used for env-scoped endpoints where the
// generated openapi schema is still on the old flat shape. Switch back to
// api.GET once the schema is regenerated against a running P3-era backend.
async function envFetch<T>(envSlug: string, path: string, init?: RequestInit): Promise<T> {
  const token = useAuthStore.getState().accessToken;
  const res = await fetch(
    `${appConfig.apiBaseUrl}/environments/${encodeURIComponent(envSlug)}${path}`, {
      ...init,
      headers: {
        'Content-Type': 'application/json',
        ...(token ? { Authorization: `Bearer ${token}` } : {}),
        'X-Cameleer-Protocol-Version': '1',
        ...init?.headers,
      },
    });
  if (!res.ok) throw new Error(`API error: ${res.status}`);
  return res.json() as Promise<T>;
}

export function useExecutionStats(
  timeFrom: string | undefined,
  timeTo: string | undefined,
  routeId?: string,
  application?: string,
  environment?: string,
) {
  const live = useLiveQuery(10_000);
  return useQuery({
    queryKey: ['executions', 'stats', environment, timeFrom, timeTo, routeId, application],
    queryFn: async () => {
      const params = new URLSearchParams({ from: timeFrom! });
      if (timeTo) params.set('to', timeTo);
      if (routeId) params.set('routeId', routeId);
      if (application) params.set('application', application);
      return envFetch<ExecutionStats>(environment!, `/stats?${params}`);
    },
    enabled: !!timeFrom && !!environment && live.enabled,
    placeholderData: (prev) => prev,
    refetchInterval: live.refetchInterval,
  });
}

export function useAttributeKeys() {
  const environment = useEnvironmentStore((s) => s.environment);
  return useQuery({
    queryKey: ['search', 'attribute-keys', environment],
    queryFn: () => envFetch<string[]>(environment!, '/attributes/keys'),
    enabled: !!environment,
    staleTime: 60_000,
  });
}

export function useSearchExecutions(filters: SearchRequest, live = false) {
  const environment = useEnvironmentStore((s) => s.environment);
  const liveQuery = useLiveQuery(5_000);
  return useQuery({
    queryKey: ['executions', 'search', environment, filters],
    queryFn: () => envFetch<SearchResultSummary>(environment!, '/executions/search', {
      method: 'POST',
      body: JSON.stringify(filters),
    }),
    placeholderData: (prev) => prev,
    enabled: !!environment && (live ? liveQuery.enabled : true),
    refetchInterval: live ? liveQuery.refetchInterval : false,
  });
}

export function useStatsTimeseries(
  timeFrom: string | undefined,
  timeTo: string | undefined,
  routeId?: string,
  application?: string,
  environment?: string,
) {
  const live = useLiveQuery(30_000);
  return useQuery({
    queryKey: ['executions', 'timeseries', environment, timeFrom, timeTo, routeId, application],
    queryFn: async () => {
      const params = new URLSearchParams({ from: timeFrom!, buckets: '24' });
      if (timeTo) params.set('to', timeTo);
      if (routeId) params.set('routeId', routeId);
      if (application) params.set('application', application);
      return envFetch<StatsTimeseries>(environment!, `/stats/timeseries?${params}`);
    },
    enabled: !!timeFrom && !!environment && live.enabled,
    placeholderData: (prev) => prev,
    refetchInterval: live.refetchInterval,
  });
}

export function useExecutionDetail(executionId: string | null) {
  return useQuery({
    queryKey: ['executions', 'detail', executionId],
    queryFn: async () => {
      const { data, error } = await api.GET('/executions/{executionId}', {
        params: { path: { executionId: executionId! } },
      });
      if (error) throw new Error('Failed to load execution detail');
      return data!;
    },
    enabled: !!executionId,
  });
}

export function useProcessorSnapshot(
  executionId: string | null,
  index: number | null,
) {
  return useQuery({
    queryKey: ['executions', 'snapshot', executionId, index],
    queryFn: async () => {
      const { data, error } = await api.GET(
        '/executions/{executionId}/processors/{index}/snapshot',
        {
          params: {
            path: { executionId: executionId!, index: index! },
          },
        },
      );
      if (error) throw new Error('Failed to load snapshot');
      return data!;
    },
    enabled: !!executionId && index !== null,
  });
}

export function useProcessorSnapshotById(
  executionId: string | null,
  processorId: string | null,
) {
  return useQuery({
    queryKey: ['executions', 'snapshot-by-id', executionId, processorId],
    queryFn: async () => {
      const { data, error } = await api.GET(
        '/executions/{executionId}/processors/by-id/{processorId}/snapshot',
        {
          params: {
            path: { executionId: executionId!, processorId: processorId! },
          },
        },
      );
      if (error) throw new Error('Failed to load snapshot');
      return data!;
    },
    enabled: !!executionId && !!processorId,
  });
}
