import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { z } from 'zod'
import { api } from '../client'
import type { BranchProtection, BranchingModel, MergeStrategies, Webhook } from '../../types/api'

const base = (o: string, r: string) => `/api/v1/repos/${o}/${r}`

// ── Branch protections ────────────────────────────────────────────────────────

const bpSchema = z.object({
  id: z.number(), pattern: z.string(), requirePR: z.boolean(),
  blockForcePush: z.boolean(), allowedUsers: z.string(), createdAt: z.string(),
})

export function useBranchProtections(owner: string, repo: string) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'branch-protections'],
    queryFn: () => api.get<BranchProtection[]>(`${base(owner, repo)}/branch-protections`, z.array(bpSchema)),
    enabled: Boolean(owner && repo),
  })
}

export function useCreateBranchProtection(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (d: { pattern: string; requirePR: boolean; blockForcePush: boolean; allowedUsers: string }) =>
      api.post<BranchProtection>(`${base(owner, repo)}/branch-protections`, bpSchema, d),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'branch-protections'] }),
  })
}

export function useUpdateBranchProtection(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: ({ id, ...d }: { id: number; requirePR: boolean; blockForcePush: boolean; allowedUsers: string }) =>
      api.patch<BranchProtection>(`${base(owner, repo)}/branch-protections/${id}`, bpSchema, d),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'branch-protections'] }),
  })
}

export function useDeleteBranchProtection(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (id: number) => api.delete(`${base(owner, repo)}/branch-protections/${id}`, z.any()),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'branch-protections'] }),
  })
}

// ── Branching model ───────────────────────────────────────────────────────────

const bmSchema = z.object({
  enabled: z.boolean(), featurePrefix: z.string(), bugfixPrefix: z.string(),
  releasePrefix: z.string(), hotfixPrefix: z.string(),
})

export function useBranchingModel(owner: string, repo: string) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'branching-model'],
    queryFn: () => api.get<BranchingModel>(`${base(owner, repo)}/branching-model`, bmSchema),
    enabled: Boolean(owner && repo),
  })
}

export function useUpdateBranchingModel(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (d: BranchingModel) =>
      api.put<BranchingModel>(`${base(owner, repo)}/branching-model`, bmSchema, d),
    onSuccess: (d) => qc.setQueryData(['repos', owner, repo, 'branching-model'], d),
  })
}

// ── Merge strategies ──────────────────────────────────────────────────────────

const msSchema = z.object({
  allowMergeCommit: z.boolean(), allowSquash: z.boolean(), allowRebase: z.boolean(),
})

export function useMergeStrategies(owner: string, repo: string) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'merge-strategies'],
    queryFn: () => api.get<MergeStrategies>(`${base(owner, repo)}/merge-strategies`, msSchema),
    enabled: Boolean(owner && repo),
  })
}

export function useUpdateMergeStrategies(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (d: MergeStrategies) =>
      api.put<MergeStrategies>(`${base(owner, repo)}/merge-strategies`, msSchema, d),
    onSuccess: (d) => qc.setQueryData(['repos', owner, repo, 'merge-strategies'], d),
  })
}

// ── Webhooks ──────────────────────────────────────────────────────────────────

const webhookSchema = z.object({
  id: z.number(), title: z.string(), url: z.string(), events: z.string(),
  active: z.boolean(), hasSecret: z.boolean(), lastStatus: z.number(),
  lastDeliveredAt: z.string().nullable().optional(), createdAt: z.string(),
})

export function useWebhooks(owner: string, repo: string) {
  return useQuery({
    queryKey: ['repos', owner, repo, 'webhooks'],
    queryFn: () => api.get<Webhook[]>(`${base(owner, repo)}/webhooks`, z.array(webhookSchema)),
    enabled: Boolean(owner && repo),
  })
}

export function useCreateWebhook(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (d: { title: string; url: string; secret?: string; events: string; active: boolean }) =>
      api.post<Webhook>(`${base(owner, repo)}/webhooks`, webhookSchema, d),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'webhooks'] }),
  })
}

export function useUpdateWebhook(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: ({ id, ...d }: { id: number; title: string; url: string; secret?: string; events: string; active: boolean }) =>
      api.patch<Webhook>(`${base(owner, repo)}/webhooks/${id}`, webhookSchema, d),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'webhooks'] }),
  })
}

export function useDeleteWebhook(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (id: number) => api.delete(`${base(owner, repo)}/webhooks/${id}`, z.any()),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'webhooks'] }),
  })
}

export function useTestWebhook(owner: string, repo: string) {
  const qc = useQueryClient()
  return useMutation({
    mutationFn: (id: number) =>
      api.post<{ status: number; ok: boolean }>(`${base(owner, repo)}/webhooks/${id}/test`,
        z.object({ status: z.number(), ok: z.boolean() }), {}),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['repos', owner, repo, 'webhooks'] }),
  })
}
