import { supabase } from '@/lib/supabase'
import type { Activity, ActivityResourceAssignment } from '@/domain/types'

function fromRow(
  row: Record<string, unknown>,
  assignedResources: ActivityResourceAssignment[],
  automatedAssignedResources: ActivityResourceAssignment[],
): Activity {
  return {
    id: row.id as string,
    processId: row.process_id as string,
    bpmnElementId: row.bpmn_element_id as string,
    name: (row.name as string) ?? '',
    type: (row.type as Activity['type']) ?? 'task',
    directCostFixed: Number(row.direct_cost_fixed ?? 0),
    executionTimeMinutes: Number(row.execution_time_minutes ?? 0),
    automatable: Boolean(row.automatable),
    automatedCostFixed: Number(row.automated_cost_fixed ?? 0),
    automatedTimeMinutes: Number(row.automated_time_minutes ?? 0),
    assignedResources,
    automatedAssignedResources,
  }
}

function assignmentFromRow(row: Record<string, unknown>): ActivityResourceAssignment {
  return {
    resourceId: row.resource_id as string,
    utilizationMinutes: Number(row.utilization_minutes ?? 0),
    units: Number(row.units ?? 1),
  }
}

// Extrae assignments de la relación anidada que Supabase devuelve con select('*, activity_resource_assignments(*)')
function extractAssignments(row: Record<string, unknown>): {
  actual: ActivityResourceAssignment[]
  automated: ActivityResourceAssignment[]
} {
  const raw = (row.activity_resource_assignments as Array<Record<string, unknown>>) ?? []
  return {
    actual: raw.filter((a) => a.scenario === 'actual').map(assignmentFromRow),
    automated: raw.filter((a) => a.scenario === 'automated').map(assignmentFromRow),
  }
}

export const supabaseActivityRepo = {
  async save(activity: Activity, userId: string): Promise<void> {
    const { error: actError } = await supabase.from('activities').upsert({
      id: activity.id,
      process_id: activity.processId,
      bpmn_element_id: activity.bpmnElementId,
      name: activity.name,
      type: activity.type,
      direct_cost_fixed: activity.directCostFixed,
      execution_time_minutes: activity.executionTimeMinutes,
      automatable: activity.automatable,
      automated_cost_fixed: activity.automatedCostFixed,
      automated_time_minutes: activity.automatedTimeMinutes,
      updated_by: userId,
      updated_at: new Date().toISOString(),
    })
    if (actError) throw actError

    const { error: delError } = await supabase
      .from('activity_resource_assignments')
      .delete()
      .eq('activity_id', activity.id)
    if (delError) throw delError

    const assignments = [
      ...activity.assignedResources.map((r) => ({
        activity_id: activity.id,
        resource_id: r.resourceId,
        utilization_minutes: r.utilizationMinutes,
        units: r.units,
        scenario: 'actual',
      })),
      ...(activity.automatedAssignedResources ?? []).map((r) => ({
        activity_id: activity.id,
        resource_id: r.resourceId,
        utilization_minutes: r.utilizationMinutes,
        units: r.units,
        scenario: 'automated',
      })),
    ]

    if (assignments.length > 0) {
      const { error: insError } = await supabase
        .from('activity_resource_assignments')
        .insert(assignments)
      if (insError) throw insError
    }
  },

  // Bulk insert optimizado: 3 round-trips totales sin importar el número de actividades
  async saveMany(activities: Activity[], userId: string): Promise<void> {
    if (activities.length === 0) return

    const now = new Date().toISOString()

    const { error: actError } = await supabase.from('activities').upsert(
      activities.map((a) => ({
        id: a.id,
        process_id: a.processId,
        bpmn_element_id: a.bpmnElementId,
        name: a.name,
        type: a.type,
        direct_cost_fixed: a.directCostFixed,
        execution_time_minutes: a.executionTimeMinutes,
        automatable: a.automatable,
        automated_cost_fixed: a.automatedCostFixed,
        automated_time_minutes: a.automatedTimeMinutes,
        updated_by: userId,
        updated_at: now,
      }))
    )
    if (actError) throw actError

    const activityIds = activities.map((a) => a.id)
    const { error: delError } = await supabase
      .from('activity_resource_assignments')
      .delete()
      .in('activity_id', activityIds)
    if (delError) throw delError

    const assignments = activities.flatMap((a) => [
      ...a.assignedResources.map((r) => ({
        activity_id: a.id,
        resource_id: r.resourceId,
        utilization_minutes: r.utilizationMinutes,
        units: r.units,
        scenario: 'actual',
      })),
      ...(a.automatedAssignedResources ?? []).map((r) => ({
        activity_id: a.id,
        resource_id: r.resourceId,
        utilization_minutes: r.utilizationMinutes,
        units: r.units,
        scenario: 'automated',
      })),
    ])

    if (assignments.length > 0) {
      const { error: insError } = await supabase
        .from('activity_resource_assignments')
        .insert(assignments)
      if (insError) throw insError
    }
  },

  // Un solo round-trip: activities + assignments anidados en una query
  async getByProcess(processId: string): Promise<Activity[]> {
    const { data, error } = await supabase
      .from('activities')
      .select('*, activity_resource_assignments(*)')
      .eq('process_id', processId)
    if (error) throw error

    return (data ?? []).map((row) => {
      const { actual, automated } = extractAssignments(row as Record<string, unknown>)
      return fromRow(row as Record<string, unknown>, actual, automated)
    })
  },

  // Un solo round-trip: actividad + assignments anidados
  async getByBpmnElementId(processId: string, bpmnElementId: string): Promise<Activity | undefined> {
    const { data, error } = await supabase
      .from('activities')
      .select('*, activity_resource_assignments(*)')
      .eq('process_id', processId)
      .eq('bpmn_element_id', bpmnElementId)
      .single()
    if (error) return undefined

    const { actual, automated } = extractAssignments(data as Record<string, unknown>)
    return fromRow(data as Record<string, unknown>, actual, automated)
  },

  async deleteByProcess(processId: string): Promise<void> {
    // CASCADE elimina activity_resource_assignments automáticamente
    const { error } = await supabase.from('activities').delete().eq('process_id', processId)
    if (error) throw error
  },
}
