/**
 * Calendar entries.
 *
 * The only rows the calendar owns. Everything else on it is projected from
 * a record that already carries the date; these are the human-owned items
 * that have nowhere else to live. So nothing here restates a deadline that a
 * contract, an obligation or an authorisation already holds — an entry is the
 * WORK before the date, which is the half a deal desk actually schedules.
 *
 * Placement is by quarter fraction rather than by a fixed offset wherever the
 * item has to be visible. The page opens on the current quarter, and an entry
 * pinned to `at(+45)` spends a third of the year in a quarter nobody is looking
 * at. The two genuinely urgent items keep their day offsets, because "before
 * the hold lapses" is a claim about this week, not about the quarter.
 */
import { eq } from 'drizzle-orm';
import { accounts, calendarEntries } from '../../schema/index';
import type { DemoContext } from './index';

export async function seedCalendar(
  context: DemoContext,
  ownerUserId: string | null,
): Promise<{ total: number; added: number }> {
  const { db, prefix, at, quarterAt } = context;

  const accountIdByName = async (name: string): Promise<string | null> => {
    const [row] = await db
      .select({ id: accounts.id })
      .from(accounts)
      .where(eq(accounts.name, name))
      .limit(1);
    return row?.id ?? null;
  };

  const halcyonId = await accountIdByName(`${prefix}Halcyon Research`);
  const tessellateId = await accountIdByName(`${prefix}Tessellate Labs`);
  const meridianId = await accountIdByName(`${prefix}Meridian Sovereign Cloud`);

  /*
   * Ahead of the export licence, whichever way the licence date resolved.
   *
   * The licence in `compliance.ts` expires at the earlier of +24 days and 93%
   * through the quarter; taking the earlier of +10 days and 80% of the quarter
   * is before it under both branches, without either file having to know which
   * branch the other took.
   */
  const beforeTheLicenceLapses = (): Date => {
    const target = at(10);
    const lastCall = quarterAt(0, 0.8);
    return target < lastCall ? target : lastCall;
  };

  const CALENDAR_ENTRIES = [
    {
      title: `${prefix}Q business review — Halcyon Research`,
      kind: 'qbr' as const,
      description: 'Utilisation against the reserved block, and the expansion case.',
      startsAt: quarterAt(0, 0.7),
      durationMinutes: 90,
      accountId: halcyonId,
    },
    {
      title: `${prefix}Renewal check-in — Nebius`,
      kind: 'meeting' as const,
      // A fortnight ahead of the +21 renewal notice obligation, which is the
      // point: the reminder has to land before the deadline, not on it.
      description: 'Decide whether to give notice before the 90-day window closes.',
      startsAt: at(7),
      durationMinutes: 45,
      accountId: null,
    },
    {
      title: `${prefix}Export-control review — Tessellate ownership change`,
      kind: 'meeting' as const,
      // The one determination on the book sitting at `needs_review`. The hold
      // it blocks lapses inside a fortnight, so this is the meeting that either
      // converts the deal or releases the capacity to someone else.
      description:
        'Counsel on the Hong Kong holding structure and whether the community pool ' +
        'can evidence physical control. The hold lapses before the month is out.',
      startsAt: at(4),
      durationMinutes: 60,
      accountId: tessellateId,
    },
    {
      title: `${prefix}Licence renewal — Meridian Sovereign Cloud`,
      kind: 'meeting' as const,
      description:
        'The export licence everything sold to this account rests on expires this ' +
        'quarter. Open the renewal, and evidence the end-use reporting condition.',
      startsAt: beforeTheLicenceLapses(),
      durationMinutes: 60,
      accountId: meridianId,
    },
    {
      title: `${prefix}Renewal decision — H200 anchor block`,
      kind: 'internal' as const,
      // Not the notice deadline itself, which lives on the MSA as an obligation
      // and is projected from there. This is the meeting at which renew, resize
      // or exit is actually chosen, which has to happen while notice is still
      // possible.
      description:
        'Renew, resize or exit the anchor block. Needs the utilisation and margin ' +
        'numbers in the room, and it has to conclude while notice can still be served.',
      startsAt: quarterAt(0, 0.6),
      durationMinutes: 60,
      accountId: null,
    },
    {
      title: `${prefix}True-up preparation — take-or-pay shortfall`,
      kind: 'reminder' as const,
      // The true-up date itself is a contract obligation. What has no home is
      // the week of reconciliation before it, which is when a disputed number
      // can still be fixed rather than argued about after the invoice.
      description:
        'Reconcile hours drawn against the 100% floor before the true-up falls due. ' +
        'Unsold hours are already paid for; the shortfall is what becomes payable.',
      startsAt: quarterAt(0, 0.85),
      durationMinutes: 30,
      accountId: null,
    },
    {
      title: `${prefix}Pipeline review — next quarter commit`,
      kind: 'internal' as const,
      description: 'Weighted pipeline against the number, before the quarter opens.',
      startsAt: quarterAt(1, 0.02),
      durationMinutes: 60,
      accountId: null,
    },
    {
      title: `${prefix}Blackwell availability campaign`,
      kind: 'campaign' as const,
      description: 'Outbound week against accounts waiting on B200 capacity.',
      startsAt: quarterAt(0, 0.45),
      // A span, not a point — the calendar must render both.
      durationMinutes: 5 * 24 * 60,
      accountId: null,
    },
  ];

  let entriesAdded = 0;
  for (const entry of CALENDAR_ENTRIES) {
    const [existingEntry] = await db
      .select({ id: calendarEntries.id })
      .from(calendarEntries)
      .where(eq(calendarEntries.title, entry.title))
      .limit(1);
    if (existingEntry) continue;
    await db.insert(calendarEntries).values({
      title: entry.title,
      description: entry.description,
      kind: entry.kind,
      startsAt: entry.startsAt,
      endsAt: new Date(entry.startsAt.getTime() + entry.durationMinutes * 60_000),
      allDay: entry.durationMinutes >= 24 * 60,
      accountId: entry.accountId,
      ownerUserId,
      createdByUserId: ownerUserId,
    });
    entriesAdded += 1;
  }

  return { total: CALENDAR_ENTRIES.length, added: entriesAdded };
}
