'use server'

import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
import { createClient } from '@/lib/supabase/server'
import { getAppOrg } from '@/lib/org'
import { getEffectiveUser } from '@/lib/effective-user'
import { guardTeam, guardTeamMember } from '@/lib/view-as-guards'

function fail(msg: string, editId?: string): never {
  const params = new URLSearchParams({ error: msg })
  if (editId) params.set('edit', editId)
  redirect(`/team?${params.toString()}`)
}

function parseProportion(raw: FormDataEntryValue | null, editId?: string): number {
  if (raw == null || raw === '') fail('Proportion is required.', editId)
  const s = String(raw).trim().replace(/%$/, '')
  const n = Number(s)
  if (Number.isNaN(n)) fail('Proportion must be a number.', editId)
  const p = n > 1 ? n / 100 : n
  if (p < 0 || p > 1) fail('Proportion must be between 0 and 1 (or 0% and 100%).', editId)
  return Math.round(p * 100000) / 100000
}

function emailLooksValid(s: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s)
}

function readCommon(formData: FormData, editId?: string) {
  const email = String(formData.get('email') ?? '').trim().toLowerCase()
  const displayName = String(formData.get('display_name') ?? '').trim()
  const consolidateAs = String(formData.get('consolidate_as') ?? '').trim() || null
  const isActive = formData.get('is_active') === 'on'
  const notes = String(formData.get('notes') ?? '').trim() || null

  if (!email || !emailLooksValid(email)) fail('A valid email is required.', editId)
  if (!displayName) fail('Display name is required.', editId)

  const rate_proportion = parseProportion(formData.get('rate_proportion'), editId)

  // billout_rate_usd is owner-only on the form; if the field isn't
  // present (manager-rendered form), keep the column out of the payload
  // entirely so we don't accidentally null out an existing value.
  const payload: Record<string, unknown> = {
    email,
    display_name: displayName,
    rate_proportion,
    consolidate_as: consolidateAs,
    is_active: isActive,
    notes,
  }
  const billoutRaw = formData.get('billout_rate_usd')
  if (billoutRaw !== null) {
    const s = String(billoutRaw).trim()
    if (s === '') {
      payload.billout_rate_usd = null
    } else {
      const n = Number(s)
      if (!Number.isFinite(n) || n < 0) {
        fail('Billout rate must be a non-negative number or blank.', editId)
      }
      payload.billout_rate_usd = Math.round(n * 100) / 100
    }
  }
  // Cost rate is per-source-hour. Blank = NULL (entries get NULL
  // billout_cost_usd and the project margin shows them as
  // "cost unknown" until the rate is filled in).
  const costRaw = formData.get('cost_rate_usd')
  if (costRaw !== null) {
    const s = String(costRaw).trim()
    if (s === '') {
      payload.cost_rate_usd = null
    } else {
      const n = Number(s)
      if (!Number.isFinite(n) || n < 0) {
        fail('Cost rate must be a non-negative number or blank.', editId)
      }
      payload.cost_rate_usd = Math.round(n * 100) / 100
    }
  }
  return payload
}

export async function createTeamMember(formData: FormData) {
  const supabase = await createClient()
  const org = await getAppOrg(supabase)
  if (!org) fail('Organization not found.')

  const teamId = String(formData.get('team_id') ?? '')
  if (!teamId) fail('Missing team id.')

  const eu = await getEffectiveUser(supabase, org.id)
  const vasError = await guardTeam(supabase, eu, org.id, teamId)
  if (vasError) fail(vasError)

  const payload = readCommon(formData)
  const { error } = await supabase
    .from('team_members')
    .insert({ org_id: org.id, team_id: teamId, ...payload })

  if (error) {
    if (error.code === '23505')
      fail(`${payload.email} is already in this team.`)
    fail(error.message)
  }
  revalidatePath('/team')
  redirect('/team')
}

export async function updateTeamMember(formData: FormData) {
  const id = String(formData.get('id') ?? '')
  if (!id) fail('Missing team member id.')

  const supabase = await createClient()
  const org = await getAppOrg(supabase)
  if (!org) fail('Organization not found.', id)

  const eu = await getEffectiveUser(supabase, org.id)
  const vasError = await guardTeamMember(supabase, eu, org.id, id)
  if (vasError) fail(vasError, id)

  const payload = readCommon(formData, id)
  // Don't allow moving a member between teams via this form — would
  // need a separate "move" action. Just update non-team fields.
  const { error } = await supabase
    .from('team_members')
    .update(payload)
    .eq('id', id)
    .eq('org_id', org.id)

  if (error) {
    if (error.code === '23505')
      fail(`${payload.email} is already in this team.`, id)
    fail(error.message, id)
  }
  revalidatePath('/team')
  redirect('/team')
}

export async function deleteTeamMember(formData: FormData) {
  const id = String(formData.get('id') ?? '')
  if (!id) fail('Missing team member id.')

  const supabase = await createClient()
  const org = await getAppOrg(supabase)
  if (!org) fail('Organization not found.')

  const eu = await getEffectiveUser(supabase, org.id)
  const vasError = await guardTeamMember(supabase, eu, org.id, id)
  if (vasError) fail(vasError)

  const { error } = await supabase
    .from('team_members')
    .delete()
    .eq('id', id)
    .eq('org_id', org.id)

  if (error) fail(error.message)
  revalidatePath('/team')
  redirect('/team')
}
