import { z } from 'zod'
import { pikkuFunc } from '#pikku/pikku-types.gen.js'
import { isManagingDirector } from '../../lib/auth-helpers.js'

export const AddMemberInput = z.object({
  companyId: z.string(),
  email: z.string().email(),
  displayName: z.string().min(2),
  role: z.enum(['managing_director', 'shareholder', 'angel']),
  shares: z.number().int().nonnegative().nullable().optional(),
})

export const AddMemberOutput = z.object({ memberId: z.string() })

export const addMember = pikkuFunc({
  expose: true,
  description: 'Add a member to the company. Caller must be managing_director.',
  input: AddMemberInput,
  output: AddMemberOutput,
  permissions: { md: [isManagingDirector] },
  func: async ({ kysely, audit }, data) => {
    const incoming = data.shares ?? 0
    if (incoming > 0) {
      const company = await kysely
        .selectFrom('company')
        .select(['totalShares'])
        .where('companyId', '=', data.companyId)
        .executeTakeFirstOrThrow()
      const assignedRow = await kysely
        .selectFrom('companyMember')
        .select((eb) => eb.fn.sum<number>('shares').as('total'))
        .where('companyId', '=', data.companyId)
        .executeTakeFirst()
      const assigned = Number(assignedRow?.total ?? 0)
      if (assigned + incoming > company.totalShares) {
        const remaining = Math.max(0, company.totalShares - assigned)
        throw new Error(
          `Shares exceed company total. ${remaining} of ${company.totalShares} remaining.`,
        )
      }
    }

    const email = data.email.trim().toLowerCase()
    let user = await kysely
      .selectFrom('user')
      .selectAll()
      .where('email', '=', email)
      .executeTakeFirst()
    if (!user) {
      const newId = crypto.randomUUID()
      const now = new Date().toISOString()
      await kysely
        .insertInto('user')
        .values({
          id: newId,
          name: data.displayName,
          email,
          emailVerified: 0,
          displayName: data.displayName,
          createdAt: now,
          updatedAt: now,
        } as any)
        .execute()
      user = await kysely
        .selectFrom('user')
        .selectAll()
        .where('email', '=', email)
        .executeTakeFirstOrThrow()
    }

    const member = await kysely
      .insertInto('companyMember')
      .values({
        companyId: data.companyId,
        userId: (user as any).id,
        role: data.role,
        shares: data.shares ?? null,
      })
      .returning(['memberId'])
      .executeTakeFirstOrThrow()

    await audit.onInsert('companyMember', member.memberId, {
      companyId: data.companyId,
      userId: (user as any).id,
      role: data.role,
      shares: data.shares ?? null,
    })

    return { memberId: member.memberId }
  },
})
