/**
 * Test factory helpers.
 *
 * Two flavours:
 *  1. Async DB-inserting factories (makePort, makeClient, makeBerth, makeYacht,
 *     makeCompany, ...) - insert a row via the app's `db` handle and return the
 *     inserted record. Use these from integration tests that need real FK /
 *     unique-index enforcement. They require DATABASE_URL to be reachable.
 *  2. Plain-data helpers (makeAuditMeta, makeCreateClientInput, makeCreate*)
 *     - return in-memory objects suitable for unit tests with mocked `db`.
 */

import { and, eq, sql } from 'drizzle-orm';
import { db } from '@/lib/db';
import { ports, type NewPort, type Port } from '@/lib/db/schema/ports';
import { clients, type NewClient, type Client } from '@/lib/db/schema/clients';
import { berths, type NewBerth, type Berth } from '@/lib/db/schema/berths';
import { yachts, yachtOwnershipHistory, type NewYacht, type Yacht } from '@/lib/db/schema/yachts';
import {
  companies,
  companyMemberships,
  type NewCompany,
  type Company,
} from '@/lib/db/schema/companies';
import { berthTenancies, type BerthTenancy } from '@/lib/db/schema/tenancies';

// ─── Port ────────────────────────────────────────────────────────────────────

export async function makePort(args?: { overrides?: Partial<NewPort> }): Promise<Port> {
  const suffix = Math.random().toString(36).slice(2, 10);
  const [port] = await db
    .insert(ports)
    .values({
      name: args?.overrides?.name ?? `Test Port ${suffix}`,
      slug: args?.overrides?.slug ?? `test-port-${suffix}`,
      ...args?.overrides,
    })
    .returning();
  return port!;
}

// ─── Client ──────────────────────────────────────────────────────────────────

export async function makeClient(args: {
  portId: string;
  overrides?: Partial<NewClient>;
}): Promise<Client> {
  const [client] = await db
    .insert(clients)
    .values({
      portId: args.portId,
      fullName: args.overrides?.fullName ?? `Test Client ${Math.random().toString(36).slice(2, 8)}`,
      ...args.overrides,
    })
    .returning();
  return client!;
}

// ─── Berth ────────────────────────────────────────────────────────────────────

export async function makeBerth(args: {
  portId: string;
  overrides?: Partial<NewBerth>;
}): Promise<Berth> {
  const [berth] = await db
    .insert(berths)
    .values({
      portId: args.portId,
      mooringNumber: args.overrides?.mooringNumber ?? `B-${Math.random().toString(36).slice(2, 8)}`,
      ...args.overrides,
    })
    .returning();
  return berth!;
}

// ─── Yacht ───────────────────────────────────────────────────────────────────

export async function makeYacht(args: {
  portId: string;
  ownerType: 'client' | 'company';
  ownerId: string;
  name?: string;
  status?: 'active' | 'retired' | 'sold_away';
  hullNumber?: string;
  registration?: string;
  overrides?: Partial<NewYacht>;
}): Promise<Yacht> {
  const [yacht] = await db
    .insert(yachts)
    .values({
      portId: args.portId,
      name: args.name ?? args.overrides?.name ?? `Yacht ${Math.random().toString(36).slice(2, 8)}`,
      currentOwnerType: args.ownerType,
      currentOwnerId: args.ownerId,
      ...(args.status !== undefined ? { status: args.status } : {}),
      ...(args.hullNumber !== undefined ? { hullNumber: args.hullNumber } : {}),
      ...(args.registration !== undefined ? { registration: args.registration } : {}),
      ...args.overrides,
    })
    .returning();
  await db.insert(yachtOwnershipHistory).values({
    yachtId: yacht!.id,
    ownerType: args.ownerType,
    ownerId: args.ownerId,
    startDate: new Date(),
    endDate: null,
    createdBy: 'test',
  });
  return yacht!;
}

// ─── Company ─────────────────────────────────────────────────────────────────

export async function makeCompany(args: {
  portId: string;
  overrides?: Partial<NewCompany>;
}): Promise<Company> {
  const [company] = await db
    .insert(companies)
    .values({
      portId: args.portId,
      name: args.overrides?.name ?? `Company ${Math.random().toString(36).slice(2, 8)}`,
      ...args.overrides,
    })
    .returning();
  return company!;
}

// ─── Company Membership ──────────────────────────────────────────────────────

export async function makeMembership(args: {
  companyId: string;
  clientId: string;
  role?: string;
  roleDetail?: string;
  startDate?: Date;
  endDate?: Date | null;
  isPrimary?: boolean;
  notes?: string;
}) {
  const [row] = await db
    .insert(companyMemberships)
    .values({
      companyId: args.companyId,
      clientId: args.clientId,
      role: args.role ?? 'director',
      roleDetail: args.roleDetail ?? null,
      startDate: args.startDate ?? new Date(),
      endDate: args.endDate ?? null,
      isPrimary: args.isPrimary ?? false,
      notes: args.notes ?? null,
    })
    .returning();
  if (!row) throw new Error('Failed to create membership');
  return row;
}

// ─── Berth Reservation ───────────────────────────────────────────────────────

export async function makeTenancy(args: {
  berthId: string;
  portId: string;
  clientId: string;
  yachtId: string;
  status: 'pending' | 'active' | 'ended' | 'cancelled';
  startDate?: Date;
  endDate?: Date | null;
  tenureType?: 'permanent' | 'fixed_term' | 'seasonal';
  interestId?: string;
  createdBy?: string;
  notes?: string;
}): Promise<BerthTenancy> {
  const [row] = await db
    .insert(berthTenancies)
    .values({
      berthId: args.berthId,
      portId: args.portId,
      clientId: args.clientId,
      yachtId: args.yachtId,
      interestId: args.interestId ?? null,
      status: args.status,
      startDate: args.startDate ?? new Date(),
      endDate: args.endDate ?? null,
      tenureType: args.tenureType ?? 'permanent',
      contractFileId: null,
      notes: args.notes ?? null,
      createdBy: args.createdBy ?? 'seed-user',
    })
    .returning();
  if (!row) throw new Error('Failed to create reservation');
  return row;
}

// ─── Yacht Ownership Transfer ────────────────────────────────────────────────

export async function makeOwnershipTransfer(args: {
  yachtId: string;
  newOwner: { type: 'client' | 'company'; id: string };
  effectiveDate?: Date;
  transferReason?: string;
  transferNotes?: string;
  createdBy?: string;
}) {
  const effective = args.effectiveDate ?? new Date();
  const createdBy = args.createdBy ?? 'seed-user';
  return await db.transaction(async (tx) => {
    // Close current open row
    await tx
      .update(yachtOwnershipHistory)
      .set({ endDate: effective })
      .where(
        and(
          eq(yachtOwnershipHistory.yachtId, args.yachtId),
          sql`${yachtOwnershipHistory.endDate} IS NULL`,
        ),
      );

    // Insert new open row
    const [newHistory] = await tx
      .insert(yachtOwnershipHistory)
      .values({
        yachtId: args.yachtId,
        ownerType: args.newOwner.type,
        ownerId: args.newOwner.id,
        startDate: effective,
        endDate: null,
        transferReason: args.transferReason ?? null,
        transferNotes: args.transferNotes ?? null,
        createdBy,
      })
      .returning();

    // Update yacht's denormalized current owner
    const [updated] = await tx
      .update(yachts)
      .set({
        currentOwnerType: args.newOwner.type,
        currentOwnerId: args.newOwner.id,
        updatedAt: new Date(),
      })
      .where(eq(yachts.id, args.yachtId))
      .returning();

    return { history: newHistory!, yacht: updated! };
  });
}

// ─── Webhook ──────────────────────────────────────────────────────────────────

export interface WebhookData {
  id: string;
  portId: string;
  name: string;
  url: string;
  secret: string | null;
  events: string[];
  isActive: boolean;
  createdBy: string;
  createdAt: Date;
  updatedAt: Date;
}

export function makeWebhook(overrides?: Partial<WebhookData>): WebhookData {
  return {
    id: crypto.randomUUID(),
    portId: crypto.randomUUID(),
    name: 'Test Webhook',
    url: 'https://example.com/webhook',
    secret: null,
    events: ['client.created'],
    isActive: true,
    createdBy: crypto.randomUUID(),
    createdAt: new Date(),
    updatedAt: new Date(),
    ...overrides,
  };
}

// ─── Audit Log ────────────────────────────────────────────────────────────────

export interface AuditMeta {
  userId: string;
  portId: string;
  ipAddress: string;
  userAgent: string;
}

export function makeAuditMeta(overrides?: Partial<AuditMeta>): AuditMeta {
  return {
    userId: crypto.randomUUID(),
    portId: crypto.randomUUID(),
    ipAddress: '127.0.0.1',
    userAgent: 'vitest/1.0',
    ...overrides,
  };
}

// ─── Auth Context ─────────────────────────────────────────────────────────────

import type { RolePermissions } from '@/lib/db/schema/users';

/** Full permissions - every action allowed. */
export function makeFullPermissions(): RolePermissions {
  return {
    clients: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      merge: true,
      export: true,
      gdpr_export: true,
    },
    interests: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      change_stage: true,
      override_stage: true,
      generate_eoi: true,
      export: true,
    },
    berths: {
      view: true,
      edit: true,
      import: true,
      manage_waiting_list: true,
      update_prices: true,
    },
    documents: {
      view: true,
      create: true,
      edit: true,
      send_for_signing: true,
      upload_signed: true,
      delete: true,
      manage_folders: true,
    },
    expenses: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      export: true,
      scan_receipt: true,
    },
    invoices: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      send: true,
      record_payment: true,
      export: true,
    },
    payments: { view: true, record: true, delete: true },
    files: { view: true, upload: true, edit: true, delete: true, manage_folders: true },
    email: { view: true, send: true, configure_account: true },
    reminders: {
      view_own: true,
      view_all: true,
      create: true,
      edit_own: true,
      edit_all: true,
      assign_others: true,
    },
    calendar: { connect: true, view_events: true },
    reports: { view_dashboard: true, view_analytics: true, export: true },
    document_templates: { view: true, generate: true, manage: true },
    yachts: { view: true, create: true, edit: true, delete: true, transfer: true },
    companies: { view: true, create: true, edit: true, delete: true },
    memberships: { view: true, manage: true },
    tenancies: { view: true, manage: true, cancel: true },
    admin: {
      manage_users: true,
      view_audit_log: true,
      manage_settings: true,
      manage_webhooks: true,
      manage_reports: true,
      manage_custom_fields: true,
      manage_forms: true,
      manage_tags: true,
      system_backup: true,
      permanently_delete_clients: true,
    },
    residential_clients: { view: true, create: true, edit: true, delete: true },
    residential_interests: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      change_stage: true,
    },
    inquiries: { view: true, manage: true },
    client_groups: { view: true, manage: true },
  };
}

/** Read-only viewer permissions - no create/update/delete. */
export function makeViewerPermissions(): RolePermissions {
  return {
    clients: {
      view: true,
      create: false,
      edit: false,
      delete: false,
      merge: false,
      export: false,
      gdpr_export: false,
    },
    interests: {
      view: true,
      create: false,
      edit: false,
      delete: false,
      change_stage: false,
      override_stage: false,
      generate_eoi: false,
      export: false,
    },
    berths: {
      view: true,
      edit: false,
      import: false,
      manage_waiting_list: false,
      update_prices: false,
    },
    documents: {
      view: true,
      create: false,
      edit: false,
      send_for_signing: false,
      upload_signed: false,
      delete: false,
      manage_folders: false,
    },
    expenses: {
      view: true,
      create: false,
      edit: false,
      delete: false,
      export: false,
      scan_receipt: false,
    },
    invoices: {
      view: true,
      create: false,
      edit: false,
      delete: false,
      send: false,
      record_payment: false,
      export: false,
    },
    payments: { view: false, record: false, delete: false },
    files: { view: true, upload: false, edit: false, delete: false, manage_folders: false },
    email: { view: true, send: false, configure_account: false },
    reminders: {
      view_own: true,
      view_all: false,
      create: false,
      edit_own: false,
      edit_all: false,
      assign_others: false,
    },
    calendar: { connect: false, view_events: true },
    reports: { view_dashboard: true, view_analytics: false, export: false },
    document_templates: { view: true, generate: false, manage: false },
    yachts: { view: true, create: false, edit: false, delete: false, transfer: false },
    companies: { view: true, create: false, edit: false, delete: false },
    memberships: { view: true, manage: false },
    tenancies: { view: true, manage: false, cancel: false },
    admin: {
      manage_users: false,
      view_audit_log: false,
      manage_settings: false,
      manage_webhooks: false,
      manage_reports: false,
      manage_custom_fields: false,
      manage_forms: false,
      manage_tags: false,
      system_backup: false,
      permanently_delete_clients: false,
    },
    residential_clients: { view: false, create: false, edit: false, delete: false },
    residential_interests: {
      view: false,
      create: false,
      edit: false,
      delete: false,
      change_stage: false,
    },
    inquiries: { view: true, manage: false },
    client_groups: { view: true, manage: false },
  };
}

/** Sales agent permissions - own clients/interests, no admin. */
export function makeSalesAgentPermissions(): RolePermissions {
  return {
    clients: {
      view: true,
      create: true,
      edit: true,
      delete: false,
      merge: false,
      export: false,
      gdpr_export: true,
    },
    interests: {
      view: true,
      create: true,
      edit: true,
      delete: false,
      change_stage: true,
      override_stage: true,
      generate_eoi: true,
      export: false,
    },
    berths: {
      view: true,
      edit: false,
      import: false,
      manage_waiting_list: false,
      update_prices: false,
    },
    documents: {
      view: true,
      create: true,
      edit: true,
      send_for_signing: true,
      upload_signed: true,
      delete: false,
      manage_folders: false,
    },
    expenses: {
      view: true,
      create: true,
      edit: true,
      delete: false,
      export: false,
      scan_receipt: true,
    },
    invoices: {
      view: true,
      create: false,
      edit: false,
      delete: false,
      send: false,
      record_payment: false,
      export: false,
    },
    payments: { view: false, record: false, delete: false },
    files: { view: true, upload: true, edit: false, delete: false, manage_folders: false },
    email: { view: true, send: true, configure_account: false },
    reminders: {
      view_own: true,
      view_all: false,
      create: true,
      edit_own: true,
      edit_all: false,
      assign_others: false,
    },
    calendar: { connect: true, view_events: true },
    reports: { view_dashboard: true, view_analytics: false, export: false },
    document_templates: { view: true, generate: true, manage: false },
    yachts: { view: true, create: true, edit: true, delete: false, transfer: false },
    companies: { view: true, create: true, edit: false, delete: false },
    memberships: { view: true, manage: false },
    tenancies: { view: true, manage: true, cancel: false },
    admin: {
      manage_users: false,
      view_audit_log: false,
      manage_settings: false,
      manage_webhooks: false,
      manage_reports: false,
      manage_custom_fields: false,
      manage_forms: false,
      manage_tags: false,
      system_backup: false,
      permanently_delete_clients: false,
    },
    residential_clients: { view: false, create: false, edit: false, delete: false },
    residential_interests: {
      view: false,
      create: false,
      edit: false,
      delete: false,
      change_stage: false,
    },
    inquiries: { view: true, manage: true },
    client_groups: { view: true, manage: true },
  };
}

/** Sales manager - can do most things, limited admin. */
export function makeSalesManagerPermissions(): RolePermissions {
  return {
    clients: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      merge: true,
      export: true,
      gdpr_export: true,
    },
    interests: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      change_stage: true,
      override_stage: true,
      generate_eoi: true,
      export: true,
    },
    berths: {
      view: true,
      edit: true,
      import: false,
      manage_waiting_list: true,
      update_prices: true,
    },
    documents: {
      view: true,
      create: true,
      edit: true,
      send_for_signing: true,
      upload_signed: true,
      delete: true,
      manage_folders: true,
    },
    expenses: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      export: true,
      scan_receipt: true,
    },
    invoices: {
      view: true,
      create: true,
      edit: true,
      delete: false,
      send: true,
      record_payment: true,
      export: true,
    },
    payments: { view: true, record: true, delete: true },
    files: { view: true, upload: true, edit: true, delete: true, manage_folders: true },
    email: { view: true, send: true, configure_account: false },
    reminders: {
      view_own: true,
      view_all: true,
      create: true,
      edit_own: true,
      edit_all: true,
      assign_others: true,
    },
    calendar: { connect: true, view_events: true },
    reports: { view_dashboard: true, view_analytics: true, export: true },
    document_templates: { view: true, generate: true, manage: false },
    yachts: { view: true, create: true, edit: true, delete: false, transfer: true },
    companies: { view: true, create: true, edit: true, delete: false },
    memberships: { view: true, manage: true },
    tenancies: { view: true, manage: true, cancel: true },
    admin: {
      manage_users: false,
      view_audit_log: true,
      manage_settings: false,
      manage_webhooks: false,
      manage_reports: true,
      manage_custom_fields: false,
      manage_forms: false,
      manage_tags: true,
      system_backup: false,
      permanently_delete_clients: false,
    },
    residential_clients: { view: true, create: true, edit: true, delete: true },
    residential_interests: {
      view: true,
      create: true,
      edit: true,
      delete: true,
      change_stage: true,
    },
    inquiries: { view: true, manage: true },
    client_groups: { view: true, manage: true },
  };
}

/** Director - everything except system backup. */
/**
 * Director is a senior-title twin of the single "Sales" role: identical
 * capabilities, no admin/settings access (admin stays Super-Admin-only). Mirror
 * the sales-manager map so the fixture tracks the real seeded role.
 */
export function makeDirectorPermissions(): RolePermissions {
  return makeSalesManagerPermissions();
}

// ─── Minimal valid CreateClientInput ─────────────────────────────────────────
/** Returns a minimal valid CreateClientInput object for use in service calls. */
export function makeCreateClientInput(overrides?: { fullName?: string; portId?: string }) {
  return {
    fullName: overrides?.fullName ?? 'Test Client',
    contacts: [{ channel: 'email' as const, value: 'test@example.com', isPrimary: true }],
    tagIds: [] as string[],
  };
}

/** Returns a minimal valid CreateInterestInput object. */
export function makeCreateInterestInput(overrides?: {
  clientId?: string;
  pipelineStage?:
    | 'enquiry'
    | 'qualified'
    | 'nurturing'
    | 'eoi'
    | 'reservation'
    | 'deposit_paid'
    | 'contract';
}) {
  return {
    clientId: overrides?.clientId ?? crypto.randomUUID(),
    pipelineStage: overrides?.pipelineStage ?? ('enquiry' as const),
    reminderEnabled: false,
    tagIds: [] as string[],
  };
}
