import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'
import { api } from '../client'
import type { Environment, EnvironmentWithLatest, Deployment, DeployStatus } from '../../types/api'

// ── Schemas ───────────────────────────────────────────────────────────────────

const deployStatusSchema = z.enum(['pending', 'in_progress', 'success', 'failure', 'cancelled'])

const deploymentSchema = z.object({
  id: z.number(),
  envId: z.number(),
  repoId: z.number(),
  sha: z.string(),
  ref: z.string(),
  status: deployStatusSchema,
  triggeredBy: z.string(),
  description: z.string(),
  runId: z.number().nullable(),
  startedAt: z.string().nullable(),
  finishedAt: z.string().nullable(),
  createdAt: z.string(),
})

const environmentSchema = z.object({
  id: z.number(),
  repoId: z.number(),
  name: z.string(),
  url: z.string(),
  protectionRules: z.string(),
  createdAt: z.string(),
  updatedAt: z.string(),
})

const environmentWithLatestSchema = environmentSchema.extend({
  latestDeployment: deploymentSchema.nullable(),
})

// ── Queries ───────────────────────────────────────────────────────────────────

export function useEnvironments(owner: string, repo: string) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'environments'],
    queryFn: () =>
      api.get<EnvironmentWithLatest[]>(
        `/api/v1/repos/${owner}/${repo}/environments`,
        z.array(environmentWithLatestSchema),
      ),
    enabled: Boolean(owner && repo),
    refetchInterval: 15_000,
  })
}

export function useEnvironment(owner: string, repo: string, envName: string) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'environments', envName],
    queryFn: () =>
      api.get<EnvironmentWithLatest>(
        `/api/v1/repos/${owner}/${repo}/environments/${envName}`,
        environmentWithLatestSchema,
      ),
    enabled: Boolean(owner && repo && envName),
    refetchInterval: 10_000,
  })
}

export function useDeployments(owner: string, repo: string, envName: string, limit = 30) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'environments', envName, 'deployments', limit],
    queryFn: () =>
      api.get<Deployment[]>(
        `/api/v1/repos/${owner}/${repo}/environments/${envName}/deployments?limit=${limit}`,
        z.array(deploymentSchema),
      ),
    enabled: Boolean(owner && repo && envName),
    refetchInterval: 10_000,
  })
}

// ── Mutations ─────────────────────────────────────────────────────────────────

export function useCreateEnvironment(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (body: { name: string; url?: string; protectionRules?: string }) =>
      api.post<Environment>(
        `/api/v1/repos/${owner}/${repo}/environments`,
        environmentSchema,
        body,
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] })
    },
  })
}

export function useUpdateEnvironment(owner: string, repo: string, envName: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (body: { url?: string; protectionRules?: string }) =>
      api.patch<Environment>(
        `/api/v1/repos/${owner}/${repo}/environments/${envName}`,
        environmentSchema,
        body,
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] })
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments', envName] })
    },
  })
}

export function useDeleteEnvironment(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (envName: string) =>
      api.delete<void>(
        `/api/v1/repos/${owner}/${repo}/environments/${envName}`,
        z.unknown() as z.ZodType<void>,
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] })
    },
  })
}

export function useCreateDeployment(owner: string, repo: string, envName: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (body: { sha: string; ref?: string; description?: string; runId?: number }) =>
      api.post<Deployment>(
        `/api/v1/repos/${owner}/${repo}/environments/${envName}/deployments`,
        deploymentSchema,
        body,
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] })
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments', envName] })
    },
  })
}

export function useUpdateDeploymentStatus(owner: string, repo: string, envName: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: ({ deployId, status, description }: { deployId: number; status: DeployStatus; description?: string }) =>
      api.patch<Deployment>(
        `/api/v1/repos/${owner}/${repo}/environments/${envName}/deployments/${deployId}/status`,
        deploymentSchema,
        { status, description },
      ),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments'] })
      qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'environments', envName] })
    },
  })
}
