import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getSessionUser } from '@/lib/auth'
import { createAdminClient } from '@/lib/supabase/admin'
import { getCompanyContext } from '@/lib/data/companies'
import {
  approveDispatcher, reinstateMember, rejectDispatcher, remindCompany, revokeDispatcher, setDispatcherPermission, updateCarrierProfile, updateOfficialInfo,
} from '@/lib/data/carrier-company'
import { bulkInviteFreightBrokers, confirmHistoricalRelationship, inviteFreightBroker, loadBrokerCompanyInfo, sendBrokerVerificationRequest } from '@/lib/data/broker-company'
import { BULK_INVITE_LIMIT, parseEmailList } from '@/lib/domain/broker-company'
import { REJECTION_REASONS, canManageCarrierCompany } from '@/lib/domain/carrier-company'
import { publicOrigin } from '@/lib/app-url'
import type { Company, CompanyClaim, CompanyMembership } from '@/types/db'

/**
 * Broker Dashboard → Broker Company (2026-09-19). Broker-specific route; the
 * membership service underneath is shared with the carrier side under the
 * broker flow (Freight Broker wording, broker email templates, broker links).
 *
 *   GET  ?company=<id>   read-only Broker Company info (HeavyHaul admins pick any broker)
 *   POST { op, … }       approve · reject · revoke · permission · profile ·
 *                        official (HeavyHaul admin) · remind (pending agent) ·
 *                        historical_confirm { decision: yes | no } ·
 *                        invite { name, email, make_admin } — verified on the spot
 *
 * Every management op re-checks: signed in · broker or HeavyHaul admin ·
 * member of THIS company · verified · company_admin permission (or
 * HeavyHaul admin) · not revoked · company id matches.
 */

const reasonEnum = z.enum(REJECTION_REASONS.map((r) => r.value) as [string, ...string[]])
const sourceEnum = z.enum(['FMCSA', 'HIGHWAY', 'MANUAL_ADMIN', 'OTHER_VERIFIED_SOURCE'])

const schema = z.discriminatedUnion('op', [
  z.object({ op: z.literal('approve'), company_id: z.string().uuid(), membership_id: z.string().uuid() }),
  z.object({ op: z.literal('reject'), company_id: z.string().uuid(), membership_id: z.string().uuid(), reason: reasonEnum, note: z.string().trim().max(1000).optional() }),
  z.object({ op: z.literal('revoke'), company_id: z.string().uuid(), membership_id: z.string().uuid() }),
  z.object({ op: z.literal('reinstate'), company_id: z.string().uuid(), membership_id: z.string().uuid() }),
  z.object({ op: z.literal('permission'), company_id: z.string().uuid(), membership_id: z.string().uuid(), level: z.enum(['member', 'company_admin']) }),
  z.object({
    op: z.literal('profile'), company_id: z.string().uuid(),
    display_name: z.string().trim().min(1).max(160).optional(), operations_phone: z.string().trim().max(40).optional(),
    operations_email: z.string().trim().max(200).optional(), dispatch_contact: z.string().trim().max(200).optional(),
    preferred_contact: z.enum(['', 'email', 'phone', 'operations_email', 'operations_phone']).optional(), description: z.string().trim().max(2000).optional(),
  }),
  z.object({
    op: z.literal('official'), company_id: z.string().uuid(),
    official_company_email: z.string().trim().max(200).optional(), official_email_status: z.enum(['unverified', 'pending', 'verified', 'rejected']).optional(),
    official_email_verification_source: sourceEnum.nullable().optional(), verification_source: sourceEnum.nullable().optional(),
  }),
  z.object({ op: z.literal('remind') }),
  z.object({ op: z.literal('historical_confirm'), decision: z.enum(['yes', 'no']) }),
  z.object({ op: z.literal('invite'), company_id: z.string().uuid(), name: z.string().trim().min(1).max(120), email: z.string().trim().email().max(200), make_admin: z.boolean().optional() }),
  z.object({ op: z.literal('bulk_invite'), company_id: z.string().uuid(), emails: z.string().min(1).max(50_000), make_admin: z.boolean().optional() }),
])

function allowed(role: string) {
  return role === 'broker' || role === 'admin'
}

export async function GET(req: NextRequest) {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })
  if (!allowed(user.role)) return NextResponse.json({ error: 'Broker Company is part of the Broker Dashboard.' }, { status: 403 })
  return NextResponse.json(await loadBrokerCompanyInfo(user, { companyId: req.nextUrl.searchParams.get('company') }))
}

export async function POST(req: NextRequest) {
  const user = await getSessionUser()
  if (!user) return NextResponse.json({ error: 'Sign in first.' }, { status: 401 })
  if (!allowed(user.role)) return NextResponse.json({ error: 'Broker Company is part of the Broker Dashboard.' }, { status: 403 })
  const parsed = schema.safeParse(await req.json().catch(() => ({})))
  if (!parsed.success) return NextResponse.json({ error: 'Invalid request.' }, { status: 400 })
  const input = parsed.data
  const isPlatformAdmin = user.role === 'admin'
  const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? null
  const actor = { id: user.id, label: user.name || user.email, email: user.email, isPlatformAdmin, ip }

  if (input.op === 'historical_confirm') {
    if (isPlatformAdmin) return NextResponse.json({ error: 'Only the person on the record can confirm it.' }, { status: 403 })
    const r = await confirmHistoricalRelationship({ user, decision: input.decision, ip })
    return r.ok ? NextResponse.json(r) : NextResponse.json({ error: r.error }, { status: 400 })
  }

  const ctx = isPlatformAdmin ? null : await getCompanyContext(user.id)
  if (ctx && !ctx.available) return NextResponse.json({ error: 'Broker Company needs database migration 0013.' }, { status: 503 })

  if (input.op === 'remind') {
    if (!ctx?.company || !ctx.membership) return NextResponse.json({ error: 'No broker company is connected to your account.' }, { status: 400 })
    // Brokers resend the full verification request (secure links) rather than a bare reminder.
    if (ctx.claim && ctx.claim.claim_status === 'pending_corporate_approval') {
      const r = await sendBrokerVerificationRequest({ claim: ctx.claim as CompanyClaim, company: ctx.company, requester: user, origin: publicOrigin(req), kind: 'reminder' })
      return NextResponse.json({ ok: true, sentTo: r.sentTo, delivered: r.results.some((x) => x.status === 'sent') })
    }
    const r = await remindCompany({ company: ctx.company, membership: ctx.membership, actor })
    return r.ok ? NextResponse.json(r) : NextResponse.json({ error: r.error }, { status: 400 })
  }

  const admin = createAdminClient()
  const { data: companyRow } = await admin.from('companies').select('*').eq('id', input.company_id).eq('company_type', 'broker').maybeSingle()
  const company = (companyRow ?? null) as Company | null
  if (!company) return NextResponse.json({ error: 'Broker company not found.' }, { status: 404 })
  const membership = (ctx?.membership ?? null) as CompanyMembership | null
  if (!canManageCarrierCompany({ membership, companyId: company.id, viewerIsPlatformAdmin: isPlatformAdmin })) {
    return NextResponse.json({ error: 'Only a verified Company Admin of this broker company can do this.' }, { status: 403 })
  }
  if (company.locked && !isPlatformAdmin) return NextResponse.json({ error: 'This company profile is locked by HeavyHaul Agent.' }, { status: 423 })

  switch (input.op) {
    case 'approve': {
      const r = await approveDispatcher({ company, membershipId: input.membership_id, actor })
      return r.ok ? NextResponse.json({ ok: true }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'reject': {
      const reasonLabel = REJECTION_REASONS.find((x) => x.value === input.reason)?.label ?? input.reason
      const r = await rejectDispatcher({ company, membershipId: input.membership_id, reason: input.reason as (typeof REJECTION_REASONS)[number]['value'], note: input.note || null, reasonLabel, actor })
      return r.ok ? NextResponse.json({ ok: true }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'revoke': {
      const r = await revokeDispatcher({ company, membershipId: input.membership_id, actor, actorMembership: membership })
      return r.ok ? NextResponse.json({ ok: true }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'reinstate': {
      const r = await reinstateMember({ company, membershipId: input.membership_id, actor })
      return r.ok ? NextResponse.json({ ok: true }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'permission': {
      const r = await setDispatcherPermission({ company, membershipId: input.membership_id, level: input.level, actor })
      return r.ok ? NextResponse.json({ ok: true }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'profile': {
      const { op: _op, company_id: _c, ...patch } = input
      void _op; void _c
      const r = await updateCarrierProfile({ company, patch, actor })
      return r.ok ? NextResponse.json({ ok: true, changed: r.changed }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'bulk_invite': {
      const { emails, invalid } = parseEmailList(input.emails)
      if (emails.length === 0) return NextResponse.json({ error: 'No valid email addresses found in the pasted list.' }, { status: 400 })
      if (emails.length > BULK_INVITE_LIMIT) return NextResponse.json({ error: `Up to ${BULK_INVITE_LIMIT} addresses per batch — split the list.` }, { status: 400 })
      const r = await bulkInviteFreightBrokers({ company, emails, makeAdmin: !!input.make_admin, actor })
      return NextResponse.json({ ok: true, results: r.results, invalid })
    }
    case 'invite': {
      const r = await inviteFreightBroker({ company, name: input.name, email: input.email, makeAdmin: !!input.make_admin, actor })
      return r.ok ? NextResponse.json(r) : NextResponse.json({ error: r.error }, { status: 400 })
    }
    case 'official': {
      if (!isPlatformAdmin) return NextResponse.json({ error: 'Official company data is changed by a verification provider or HeavyHaul Agent.' }, { status: 403 })
      const { op: _op, company_id: _c, ...patch } = input
      void _op; void _c
      const r = await updateOfficialInfo({ company, patch, actor })
      return r.ok ? NextResponse.json({ ok: true }) : NextResponse.json({ error: r.error }, { status: 400 })
    }
  }
}
