import { z } from "zod"
import { useInfiniteQuery, useQuery } from "@tanstack/react-query"
import { paginatedSchema } from "@/lib/api/common"
import { get } from "@/lib/api/client"

const PAGE_SIZE = 20

export const searchQueryParamsSchema = z.object({
  q: z.string().optional(),
  genre: z.string().optional(),
  year: z.number().optional(),
  person_id: z.string().uuid().optional(),
  department: z.string().optional(),
  language: z.string().optional(),
  limit: z.number().optional(),
  offset: z.number().optional(),
})
export type SearchQueryParams = z.infer<typeof searchQueryParamsSchema>

export const movieSearchHitDtoSchema = z.object({
  movie_id: z.string().uuid(),
  title: z.string(),
  release_year: z.number().optional(),
  director: z.string().optional(),
  poster_path: z.string().optional(),
  genres: z.array(z.string()),
})
export type MovieSearchHitDto = z.infer<typeof movieSearchHitDtoSchema>

export const personSearchHitDtoSchema = z.object({
  person_id: z.string().uuid(),
  name: z.string(),
  known_for_department: z.string().optional(),
  profile_path: z.string().optional(),
  known_for_titles: z.array(z.string()),
})
export type PersonSearchHitDto = z.infer<typeof personSearchHitDtoSchema>

export const searchResponseSchema = z.object({
  movies: paginatedSchema(movieSearchHitDtoSchema),
  people: paginatedSchema(personSearchHitDtoSchema),
})
export type SearchResponse = z.infer<typeof searchResponseSchema>

export const personDtoSchema = z.object({
  id: z.string().uuid(),
  external_id: z.string(),
  name: z.string(),
  known_for_department: z.string().optional(),
  profile_path: z.string().optional(),
  biography: z.string().optional(),
  birthday: z.string().optional(),
  deathday: z.string().optional(),
  place_of_birth: z.string().optional(),
  also_known_as: z.array(z.string()).default([]),
  homepage: z.string().optional(),
  imdb_url: z.string().optional(),
  enriched: z.boolean().default(false),
})
export type PersonDto = z.infer<typeof personDtoSchema>

export const castCreditDtoSchema = z.object({
  movie_id: z.string().uuid(),
  title: z.string(),
  release_year: z.number().optional(),
  character: z.string(),
  poster_path: z.string().optional(),
})
export type CastCreditDto = z.infer<typeof castCreditDtoSchema>

export const crewCreditDtoSchema = z.object({
  movie_id: z.string().uuid(),
  title: z.string(),
  release_year: z.number().optional(),
  job: z.string(),
  department: z.string(),
  poster_path: z.string().optional(),
})
export type CrewCreditDto = z.infer<typeof crewCreditDtoSchema>

export const personCreditsDtoSchema = z.object({
  person: personDtoSchema,
  cast: z.array(castCreditDtoSchema),
  crew: z.array(crewCreditDtoSchema),
})
export type PersonCreditsDto = z.infer<typeof personCreditsDtoSchema>

function search(params: SearchQueryParams) {
  return get<SearchResponse>("/search", params)
}

function getPerson(id: string) {
  return get<PersonDto>(`/people/${id}`)
}

function getPersonCredits(id: string) {
  return get<PersonCreditsDto>(`/people/${id}/credits`)
}

export const searchKeys = {
  all: ["search"] as const,
  query: (params: SearchQueryParams) => [...searchKeys.all, params] as const,
  person: (id: string) => ["people", id] as const,
  personCredits: (id: string) => ["people", id, "credits"] as const,
}

export function useSearch(params: SearchQueryParams) {
  return useQuery({
    queryKey: searchKeys.query(params),
    queryFn: () => search(params),
    enabled: !!params.q || !!params.genre || !!params.person_id,
  })
}

export function useInfiniteSearch(
  params: Omit<SearchQueryParams, "limit" | "offset">,
) {
  return useInfiniteQuery({
    queryKey: searchKeys.query(params),
    queryFn: ({ pageParam = 0 }) =>
      search({ ...params, limit: PAGE_SIZE, offset: pageParam }),
    initialPageParam: 0,
    getNextPageParam: (last) => {
      const next = last.movies.offset + last.movies.limit
      return next < last.movies.total_count ? next : undefined
    },
    enabled: !!params.q || !!params.genre || !!params.person_id,
  })
}

export function usePerson(id: string) {
  return useQuery({
    queryKey: searchKeys.person(id),
    queryFn: () => getPerson(id),
    enabled: !!id,
  })
}

export function usePersonCredits(id: string) {
  return useQuery({
    queryKey: searchKeys.personCredits(id),
    queryFn: () => getPersonCredits(id),
    enabled: !!id,
  })
}
