import { supabase } from '@/lib/supabase'
import type { Resource } from '@/domain/types'

function fromRow(row: Record<string, unknown>): Resource {
  return {
    id: row.id as string,
    name: row.name as string,
    type: row.type as Resource['type'],
    costPerHour: Number(row.cost_per_hour ?? 0),
  }
}

// Solo para display — no es parte del dominio puro (mismo patrón que ProcessWithUserNames, Etapa 6)
export interface ResourceWithCreator extends Resource {
  creatorName: string
}

function fromRowWithCreator(row: Record<string, unknown>): ResourceWithCreator {
  const creator = row.creator as { name: string | null } | null
  return {
    ...fromRow(row),
    creatorName: creator?.name ?? 'Desconocido',
  }
}

export const supabaseResourceRepo = {
  async save(resource: Resource, userId: string): Promise<void> {
    const { error } = await supabase.from('resources').upsert({
      id: resource.id,
      name: resource.name,
      type: resource.type,
      cost_per_hour: resource.costPerHour,
      created_by: userId,
      updated_by: userId,
      updated_at: new Date().toISOString(),
    })
    if (error) throw error
  },

  async getAll(): Promise<Resource[]> {
    const { data, error } = await supabase
      .from('resources')
      .select('*')
      .order('name', { ascending: true })
    if (error) throw error
    return (data ?? []).map(fromRow)
  },

  // JOIN con users para resolver "creado por" en una sola query (mismo patrón que Etapa 6)
  async getAllWithCreator(): Promise<ResourceWithCreator[]> {
    const { data, error } = await supabase
      .from('resources')
      .select('*, creator:users!created_by(name)')
      .order('name', { ascending: true })
    if (error) throw error
    return (data ?? []).map((row) => fromRowWithCreator(row as Record<string, unknown>))
  },

  // Devuelve un map resourceId → cantidad de procesos DISTINTOS que usan ese recurso.
  // Una sola query para evitar N+1; agregación client-side con Set.
  async getProcessCountsPerResource(): Promise<Record<string, number>> {
    const { data, error } = await supabase
      .from('activity_resource_assignments')
      .select('resource_id, activity:activities!inner(process_id)')
    if (error) throw error
    if (!data) return {}

    const processSets: Record<string, Set<string>> = {}
    for (const row of data) {
      const resourceId = row.resource_id as string
      const processId = (row.activity as unknown as { process_id: string }).process_id
      if (!processSets[resourceId]) processSets[resourceId] = new Set()
      processSets[resourceId].add(processId)
    }
    return Object.fromEntries(
      Object.entries(processSets).map(([k, v]) => [k, v.size])
    )
  },

  // Devuelve los procesos distintos que usan el recurso (llamada on-demand al expandir fila).
  async getProcessesForResource(resourceId: string): Promise<{ id: string; name: string }[]> {
    const { data, error } = await supabase
      .from('activity_resource_assignments')
      .select('activity:activities!inner(process:processes!inner(id, name))')
      .eq('resource_id', resourceId)
    if (error) throw error
    if (!data) return []

    const seen = new Set<string>()
    const result: { id: string; name: string }[] = []
    for (const row of data) {
      const process = (row.activity as unknown as { process: { id: string; name: string } }).process
      if (!seen.has(process.id)) {
        seen.add(process.id)
        result.push({ id: process.id, name: process.name })
      }
    }
    return result
  },

  // No elimina si el recurso tiene asignaciones activas en activity_resource_assignments
  async delete(resourceId: string): Promise<void> {
    const { count, error: countError } = await supabase
      .from('activity_resource_assignments')
      .select('*', { count: 'exact', head: true })
      .eq('resource_id', resourceId)
    if (countError) throw countError
    if ((count ?? 0) > 0) {
      throw new Error('Este recurso está asignado a actividades — quitá las asignaciones antes de eliminarlo')
    }

    const { error } = await supabase.from('resources').delete().eq('id', resourceId)
    if (error) throw error
  },
}
