import type { ParticipantStatus, TripParticipant, TripRole } from '@/types/db'
import { canRemove } from '@/lib/domain/permissions'

/**
 * Which participant rows grant access to a trip (2026-09-14).
 *
 *   invited   → a live invitation; the person may open the trip
 *   active    → joined
 *   imported  → came from a historical import (a permit provider's completed
 *               order). SHOWN on the trip as a person, but grants NO access:
 *               "just because a dispatcher email appears in an old order does
 *               not mean that user should immediately see everything"
 *               (migration article §33). Becomes `active` when the person
 *               claims it after verifying their email — see
 *               `src/lib/data/imported-claims.ts`.
 *   removed   → gone; sees nothing
 *
 * Every access decision (which trips a user sees, whether an API call is
 * allowed) must filter on ACCESS_STATUSES. Display lists may keep showing
 * imported people — that is the point of importing them.
 */
export const ACCESS_STATUSES: readonly ParticipantStatus[] = ['invited', 'active']

export function grantsAccess(status: ParticipantStatus | string | null | undefined): boolean {
  return !!status && (ACCESS_STATUSES as readonly string[]).includes(status)
}

/**
 * A participant row for an admin who is not on the trip (Nash, 2026-09-17:
 * "admin has power to every single tool, even if he's not the creator or
 * not… Admin gets all the tools from everybody else").
 *
 * One builder for BOTH the API guard and the page loaders, so the tools an
 * admin sees on a trip and the calls those tools make can never disagree
 * (2026-09-18: the API admitted admins, the page still hid Upload and Order
 * permits behind a null role). Role `admin` is already accepted by every
 * per-trip gate — INVITE_RULES, EDIT_ROLES, STATUS_MANAGER_ROLES,
 * canUploadDocuments.
 *
 * The id is empty on purpose: there is no row to write to. Anything that
 * writes to the caller's OWN row (chat privacy, personal completion) must
 * use the real row, never this.
 */
export function adminParticipantFor(
  tripId: string,
  user: { id: string; email: string; name?: string | null },
): TripParticipant {
  return {
    id: '',
    trip_id: tripId,
    user_id: user.id,
    email: user.email,
    name: user.name || user.email,
    phone: null,
    phone_ext: null,
    role: 'admin',
    status: 'active',
    invited_by: null,
    completed_at: null,
    completion_prompt_dismissed_at: null,
    share_chat: true,
    created_at: new Date(0).toISOString(),
  }
}

/**
 * Who may remove a participant from a live trip (decision D17, 2026-09-30).
 *
 *   - a platform admin
 *   - whoever the invite matrix lets remove that trip role (`canRemove`)
 *   - the person whose participation fired a PERSONAL Auto-Participant rule
 *   - a Company Admin of the company whose rule fired, acting in that
 *     company's mode
 *
 * Removal never changes the rule itself (§20): the person stops being on
 * this trip, not being an Auto-Participant.
 */
export function canRemoveParticipant(params: {
  viewer: { userId: string | null; role: TripRole | string; isAdmin: boolean; activeCompanyId?: string | null; activeIsCompanyAdmin?: boolean }
  target: Pick<TripParticipant, 'user_id' | 'role' | 'addition_method' | 'triggering_user_id' | 'triggering_company_id'>
}): boolean {
  const { viewer, target } = params
  if (viewer.isAdmin) return true
  if (viewer.userId && target.user_id && viewer.userId === target.user_id) return false
  if (canRemove(viewer.role as TripRole, target.role)) return true
  if (target.addition_method === 'personal_auto_participant' && !!viewer.userId && target.triggering_user_id === viewer.userId) return true
  if (
    target.addition_method === 'company_auto_participant' &&
    !!target.triggering_company_id &&
    viewer.activeIsCompanyAdmin === true &&
    viewer.activeCompanyId === target.triggering_company_id
  ) return true
  return false
}
