import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { config } from '../../../config';
import { useAuthStore } from '../../../auth/auth-store';

export interface App {
  id: string;
  environmentId: string;
  slug: string;
  displayName: string;
  containerConfig: Record<string, unknown>;
  createdAt: string;
  updatedAt: string;
}

export interface AppVersion {
  id: string;
  appId: string;
  version: number;
  jarPath: string;
  jarChecksum: string;
  jarFilename: string;
  jarSizeBytes: number;
  detectedRuntimeType: string | null;
  detectedMainClass: string | null;
  uploadedAt: string;
}

export interface Deployment {
  id: string;
  appId: string;
  appVersionId: string;
  environmentId: string;
  status: 'STOPPED' | 'STARTING' | 'RUNNING' | 'DEGRADED' | 'STOPPING' | 'FAILED';
  targetState: string;
  deploymentStrategy: string;
  replicaStates: { index: number; containerId: string; containerName: string; status: string; oomKilled?: boolean }[];
  deployStage: string | null;
  containerId: string | null;
  containerName: string | null;
  errorMessage: string | null;
  deployedAt: string | null;
  stoppedAt: string | null;
  createdAt: string;
  deployedConfigSnapshot?: {
    jarVersionId: string;
    agentConfig: Record<string, unknown> | null;
    containerConfig: Record<string, unknown>;
    sensitiveKeys: string[] | null;
  } | null;
  createdBy: string | null;
}

/**
 * Authenticated fetch. `path` is relative to apiBaseUrl, must include the
 * leading slash. All app/deployment endpoints now live under
 * /api/v1/environments/{envSlug}/...
 */
async function apiFetch<T>(path: string, options?: RequestInit): Promise<T> {
  const token = useAuthStore.getState().accessToken;
  const res = await fetch(`${config.apiBaseUrl}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      'X-Cameleer-Protocol-Version': '1',
      ...options?.headers,
    },
  });
  if (res.status === 401 || res.status === 403) {
    useAuthStore.getState().logout();
    throw new Error('Unauthorized');
  }
  if (!res.ok) throw new Error(`API error: ${res.status}`);
  if (res.status === 204) return undefined as T;
  const text = await res.text();
  if (!text) return undefined as T;
  return JSON.parse(text);
}

function envBase(envSlug: string): string {
  return `/environments/${encodeURIComponent(envSlug)}/apps`;
}

// --- Apps ---

export function useApps(envSlug: string | undefined) {
  return useQuery({
    queryKey: ['apps', envSlug],
    queryFn: () => apiFetch<App[]>(envBase(envSlug!)),
    enabled: !!envSlug,
  });
}

export function useCreateApp() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, slug, displayName }: { envSlug: string; slug: string; displayName: string }) =>
      apiFetch<App>(envBase(envSlug), {
        method: 'POST',
        body: JSON.stringify({ slug, displayName }),
      }),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['apps'] }),
  });
}

export function useDeleteApp() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, appSlug }: { envSlug: string; appSlug: string }) =>
      apiFetch<void>(`${envBase(envSlug)}/${encodeURIComponent(appSlug)}`, { method: 'DELETE' }),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['apps'] });
      qc.invalidateQueries({ queryKey: ['catalog'] });
    },
  });
}

export function useUpdateContainerConfig() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, appSlug, config }: { envSlug: string; appSlug: string; config: Record<string, unknown> }) =>
      apiFetch<App>(`${envBase(envSlug)}/${encodeURIComponent(appSlug)}/container-config`, {
        method: 'PUT',
        body: JSON.stringify(config),
      }),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['apps'] }),
  });
}

// --- Versions ---

export function useAppVersions(envSlug: string | undefined, appSlug: string | undefined) {
  return useQuery({
    queryKey: ['apps', envSlug, appSlug, 'versions'],
    queryFn: () => apiFetch<AppVersion[]>(`${envBase(envSlug!)}/${encodeURIComponent(appSlug!)}/versions`),
    enabled: !!envSlug && !!appSlug,
  });
}

export function useUploadJar() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, appSlug, file, onProgress }: {
      envSlug: string;
      appSlug: string;
      file: File;
      onProgress?: (pct: number) => void;
    }) => {
      const token = useAuthStore.getState().accessToken;
      const form = new FormData();
      form.append('file', file);

      return new Promise<AppVersion>((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open(
          'POST',
          `${config.apiBaseUrl}${envBase(envSlug)}/${encodeURIComponent(appSlug)}/versions`,
        );
        if (token) xhr.setRequestHeader('Authorization', `Bearer ${token}`);
        xhr.setRequestHeader('X-Cameleer-Protocol-Version', '1');

        xhr.upload.onprogress = (e) => {
          if (!onProgress || !e.lengthComputable) return;
          onProgress(Math.round((e.loaded / e.total) * 100));
        };

        xhr.onload = () => {
          if (xhr.status < 200 || xhr.status >= 300) {
            reject(new Error(`Upload failed: ${xhr.status}`));
            return;
          }
          try {
            resolve(JSON.parse(xhr.responseText) as AppVersion);
          } catch (err) {
            reject(err instanceof Error ? err : new Error('Invalid response'));
          }
        };

        xhr.onerror = () => reject(new Error('Upload network error'));
        xhr.onabort = () => reject(new Error('Upload aborted'));

        xhr.send(form);
      });
    },
    onSuccess: (_data, { envSlug, appSlug }) =>
      qc.invalidateQueries({ queryKey: ['apps', envSlug, appSlug, 'versions'] }),
  });
}

// --- Deployments ---

export function useDeployments(envSlug: string | undefined, appSlug: string | undefined) {
  return useQuery({
    queryKey: ['apps', envSlug, appSlug, 'deployments'],
    queryFn: () => apiFetch<Deployment[]>(`${envBase(envSlug!)}/${encodeURIComponent(appSlug!)}/deployments`),
    enabled: !!envSlug && !!appSlug,
    refetchInterval: 5000,
  });
}

export function useCreateDeployment() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, appSlug, appVersionId }: { envSlug: string; appSlug: string; appVersionId: string }) =>
      apiFetch<Deployment>(
        `${envBase(envSlug)}/${encodeURIComponent(appSlug)}/deployments`,
        { method: 'POST', body: JSON.stringify({ appVersionId }) },
      ),
    onSuccess: (_data, { envSlug, appSlug }) =>
      qc.invalidateQueries({ queryKey: ['apps', envSlug, appSlug, 'deployments'] }),
  });
}

export function useStopDeployment() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, appSlug, deploymentId }: { envSlug: string; appSlug: string; deploymentId: string }) =>
      apiFetch<Deployment>(
        `${envBase(envSlug)}/${encodeURIComponent(appSlug)}/deployments/${deploymentId}/stop`,
        { method: 'POST' },
      ),
    onSuccess: (_data, { envSlug, appSlug }) =>
      qc.invalidateQueries({ queryKey: ['apps', envSlug, appSlug, 'deployments'] }),
  });
}

export function usePromoteDeployment() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: ({ envSlug, appSlug, deploymentId, targetEnvironment }:
        { envSlug: string; appSlug: string; deploymentId: string; targetEnvironment: string }) =>
      apiFetch<Deployment>(
        `${envBase(envSlug)}/${encodeURIComponent(appSlug)}/deployments/${deploymentId}/promote`,
        { method: 'POST', body: JSON.stringify({ targetEnvironment }) },
      ),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['apps'] }),
  });
}

// --- Dirty State ---

export interface DirtyStateDifference {
  field: string;
  staged: string;
  deployed: string;
}

export interface DirtyState {
  dirty: boolean;
  lastSuccessfulDeploymentId: string | null;
  differences: DirtyStateDifference[];
}

export function useDirtyState(envSlug: string | undefined, appSlug: string | undefined) {
  return useQuery({
    queryKey: ['apps', envSlug, appSlug, 'dirty-state'],
    queryFn: () => apiFetch<DirtyState>(
      `${envBase(envSlug!)}/${encodeURIComponent(appSlug!)}/dirty-state`,
    ),
    enabled: !!envSlug && !!appSlug,
  });
}
