import { randomUUID } from "node:crypto";
import type { Prisma, PrismaClient } from "@prisma/client";
import {
  fingerprintFeishuAppId,
  validateFeishuApplicationCredential,
  type FeishuApplicationCredentialInput,
} from "../connections/feishuApplicationConnections.js";
import {
  decryptStoredProviderCredential,
  ProviderConnectionService,
  type ProviderCredentialInput,
} from "../connections/providerConnections.js";
import { probeFeishuApplication, type FeishuReadinessProbe } from "../connections/feishuReadiness.js";
import { probeOpenRouterCredential, type ProviderReadinessProbe } from "../connections/providerReadiness.js";
import { deterministicFeishuUserId, scopedFeishuPrincipalId } from "../feishu/identityNamespace.js";
import { LocalSecretEnvelope } from "../security/secretEnvelope.js";

export interface AlphaSiloBootstrapInput {
  readonly organization: { readonly id: string; readonly slug: string; readonly name: string };
  readonly owner: { readonly openId: string; readonly displayName: string; readonly unionId?: string };
  readonly feishu: FeishuApplicationCredentialInput;
  readonly provider: ProviderCredentialInput & { readonly providerId: string };
  readonly teams?: readonly {
    readonly slug: string;
    readonly name: string;
    readonly description?: string;
  }[];
}

export interface AlphaSiloBootstrapResult {
  readonly organizationId: string;
  readonly ownerUserId: string;
  readonly feishuConnectionId: string;
  readonly initialized: boolean;
  readonly providerConfigured: boolean;
}

/**
 * Idempotently bootstrap the one Organization allowed in an Alpha Silo.
 * Secrets are accepted only in-memory and persisted as authenticated envelopes.
 */
export async function bootstrapAlphaSilo(
  prisma: PrismaClient,
  secrets: LocalSecretEnvelope,
  input: AlphaSiloBootstrapInput,
  probes: {
    readonly feishu?: FeishuReadinessProbe;
    readonly provider?: ProviderReadinessProbe;
  } = {},
): Promise<AlphaSiloBootstrapResult> {
  const normalized = validateInput(input);
  await removePristineLegacyMigrationOrganization(prisma);
  const existing = await loadExistingSilo(prisma, normalized.organization.id, normalized.owner.openId);
  let initialized = false;
  let ownerUserId: string;
  let feishuConnectionId: string;

  if (existing === null) {
    await (probes.feishu ?? probeFeishuApplication)(normalized.feishu);
    const initializedSilo = await initializeSilo(prisma, secrets, normalized);
    initialized = true;
    ownerUserId = initializedSilo.ownerUserId;
    feishuConnectionId = initializedSilo.feishuConnectionId;
  } else {
    ownerUserId = existing.ownerUserId;
    feishuConnectionId = existing.feishuConnectionId;
    const expectedFingerprint = fingerprintFeishuAppId(normalized.feishu.appId);
    if (existing.appIdentityFingerprint !== expectedFingerprint) {
      throw new Error("bootstrap Feishu app identity does not match the existing Silo");
    }
  }

  const providerService = new ProviderConnectionService(
    prisma,
    secrets,
    probes.provider ?? probeOpenRouterCredential,
  );
  const existingProviders = await providerService.list(normalized.organization.id);
  const existingProvider = existingProviders.find((connection) => connection.providerId === normalized.provider.providerId);
  if (existingProvider === undefined) {
    await providerService.rotateByok({
      organizationId: normalized.organization.id,
      actorUserId: ownerUserId,
      providerId: normalized.provider.providerId,
      baseUrl: normalized.provider.baseUrl,
      authToken: normalized.provider.authToken,
      ...(normalized.provider.anthropicApiKey !== undefined
        ? { anthropicApiKey: normalized.provider.anthropicApiKey }
        : {}),
    });
  } else if (existingProvider.status !== "ACTIVE" || existingProvider.mode !== "BYOK") {
    throw new Error(`bootstrap provider ${normalized.provider.providerId} exists but is not ACTIVE BYOK`);
  } else {
    const stored = await loadExistingProviderCredential(
      prisma,
      secrets,
      normalized.organization.id,
      normalized.provider.providerId,
    );
    if (stored.baseUrl !== normalized.provider.baseUrl || stored.authToken !== normalized.provider.authToken ||
        stored.anthropicApiKey !== (normalized.provider.anthropicApiKey ?? "")) {
      throw new Error(`bootstrap provider ${normalized.provider.providerId} credential does not match existing Silo`);
    }
  }

  await ensureBootstrapTeams(prisma, normalized.organization.id, ownerUserId, normalized.teams ?? []);

  return {
    organizationId: normalized.organization.id,
    ownerUserId,
    feishuConnectionId,
    initialized,
    providerConfigured: true,
  };
}

const LEGACY_MIGRATION_ORGANIZATION = {
  id: "org_default",
  slug: "legacy-default",
  name: "Legacy Default Organization",
  inboxId: "folder_inbox_2b99350e0db97ad0cbcb55c20ee8bafa",
} as const;

/**
 * A fresh database still receives the compatibility Organization inserted by
 * the tenant-root migration, plus its later default settings and Inbox. An
 * Alpha Silo bootstrap may replace only that exact, otherwise-unused scaffold.
 * Any tenant data or shape drift remains a hard manual-repair error.
 */
async function removePristineLegacyMigrationOrganization(prisma: PrismaClient): Promise<void> {
  await prisma.$transaction(async (tx) => {
    const organization = await tx.organization.findUnique({
      where: { id: LEGACY_MIGRATION_ORGANIZATION.id },
      include: {
        memberships: { take: 1, select: { id: true } },
        projects: { take: 1, select: { id: true } },
        teams: { take: 1, select: { id: true } },
        externalDirectoryConnections: { take: 1, select: { id: true } },
        providerConnections: { take: 1, select: { id: true } },
        feishuApplicationConnection: { select: { id: true } },
        auditEntries: { take: 1, select: { id: true } },
        projectSettings: true,
        folders: {
          take: 2,
          select: { id: true, parentId: true, name: true, sortKey: true, archivedAt: true },
        },
      },
    });
    if (organization === null) return;
    const pristine =
      organization.slug === LEGACY_MIGRATION_ORGANIZATION.slug &&
      organization.name === LEGACY_MIGRATION_ORGANIZATION.name &&
      organization.status === "ACTIVE" &&
      organization.memberships.length === 0 &&
      organization.projects.length === 0 &&
      organization.teams.length === 0 &&
      organization.externalDirectoryConnections.length === 0 &&
      organization.providerConnections.length === 0 &&
      organization.feishuApplicationConnection === null &&
      organization.auditEntries.length === 0 &&
      organization.projectSettings?.membersCanCreateProjects === true &&
      organization.folders.length === 1 &&
      organization.folders[0]?.id === LEGACY_MIGRATION_ORGANIZATION.inboxId &&
      organization.folders[0].parentId === null &&
      organization.folders[0].name === "Inbox" &&
      organization.folders[0].sortKey === "000000" &&
      organization.folders[0].archivedAt === null;
    if (pristine) {
      await tx.organization.delete({ where: { id: organization.id } });
    }
  });
}

async function ensureBootstrapTeams(
  prisma: PrismaClient,
  organizationId: string,
  ownerUserId: string,
  teams: NonNullable<AlphaSiloBootstrapInput["teams"]>,
): Promise<void> {
  await prisma.$transaction(async (tx) => {
    for (const team of teams) {
      const existing = await tx.team.findFirst({
        where: { organizationId, slug: team.slug, archivedAt: null },
        select: { id: true, name: true, description: true },
      });
      if (existing !== null && (existing.name !== team.name || existing.description !== (team.description ?? null))) {
        throw new Error(`bootstrap Team ${team.slug} does not match the existing Silo`);
      }
      const teamId = existing?.id ?? (await tx.team.create({
        data: {
          organizationId,
          slug: team.slug,
          name: team.name,
          ...(team.description !== undefined ? { description: team.description } : {}),
        },
        select: { id: true },
      })).id;
      const membership = await tx.teamMembership.findFirst({
        where: { teamId, userId: ownerUserId, revokedAt: null },
        select: { id: true },
      });
      if (membership === null) await tx.teamMembership.create({ data: { teamId, userId: ownerUserId } });
    }
  });
}

async function initializeSilo(
  prisma: PrismaClient,
  secrets: LocalSecretEnvelope,
  input: AlphaSiloBootstrapInput,
): Promise<{ readonly ownerUserId: string; readonly feishuConnectionId: string }> {
  const connectionId = randomUUID();
  const secretVersionId = randomUUID();
  const identityId = randomUUID();
  const ownerUserId = deterministicFeishuUserId(connectionId, input.owner.openId);
  const appIdentityFingerprint = fingerprintFeishuAppId(input.feishu.appId);
  const payload = validateFeishuApplicationCredential(input.feishu);
  const envelope = secrets.encryptJson({
    purpose: "feishu-application",
    organizationId: input.organization.id,
    connectionId,
    secretVersionId,
  }, payload);

  await prisma.$transaction(async (tx) => {
    const count = await tx.organization.count();
    if (count !== 0) throw new Error(`Silo bootstrap requires an empty Organization set; found ${count}`);
    await tx.organization.create({ data: { ...input.organization } });
    await tx.organizationAgentRole.createMany({
      data: [
        {
          organizationId: input.organization.id,
          roleId: "draft",
          label: "草稿",
          sortOrder: 10,
          isDefault: true,
        },
        {
          organizationId: input.organization.id,
          roleId: "review",
          label: "审校",
          sortOrder: 20,
        },
      ],
    });
    await tx.organizationProjectSettings.create({
      data: { organizationId: input.organization.id, membersCanCreateProjects: true },
    });
    await tx.folder.create({
      data: {
        organizationId: input.organization.id,
        name: "Inbox",
        kind: "SYSTEM_INBOX",
        sortKey: "000000",
      },
    });
    await tx.user.create({
      data: {
        id: ownerUserId,
        feishuOpenId: scopedFeishuPrincipalId("USER", connectionId, input.owner.openId),
        displayName: input.owner.displayName,
      },
    });
    await tx.organizationFeishuApplicationConnection.create({
      data: {
        id: connectionId,
        organizationId: input.organization.id,
        appIdentityFingerprint,
        status: "DRAFT",
      },
    });
    await tx.feishuUserIdentity.create({
      data: {
        id: identityId,
        connectionId,
        userId: ownerUserId,
        openId: input.owner.openId,
        ...(input.owner.unionId !== undefined ? { unionId: input.owner.unionId } : {}),
      },
    });
    await tx.organizationMembership.create({
      data: { organizationId: input.organization.id, userId: ownerUserId, role: "OWNER" },
    });
    for (const team of input.teams ?? []) {
      await tx.team.create({
        data: {
          organizationId: input.organization.id,
          slug: team.slug,
          name: team.name,
          ...(team.description !== undefined ? { description: team.description } : {}),
          memberships: { create: { userId: ownerUserId } },
        },
      });
    }
    await tx.feishuApplicationCredentialVersion.create({
      data: {
        id: secretVersionId,
        connectionId,
        version: 1,
        envelopeVersion: envelope.version,
        keyId: envelope.keyId,
        envelope: envelope as unknown as Prisma.InputJsonValue,
        createdByUserId: ownerUserId,
      },
    });
    await tx.organizationFeishuApplicationConnection.update({
      where: { id: connectionId },
      data: {
        status: "ACTIVE",
        activeSecretVersionId: secretVersionId,
        activatedAt: new Date(),
      },
    });
    await tx.auditEntry.create({
      data: {
        organizationId: input.organization.id,
        actorUserId: ownerUserId,
        action: "alpha_silo.bootstrapped",
        metadata: {
          connectionId,
          ownerIdentityId: identityId,
          envelopeVersion: envelope.version,
          keyId: envelope.keyId,
        },
      },
    });
  });
  return { ownerUserId, feishuConnectionId: connectionId };
}

async function loadExistingSilo(
  prisma: PrismaClient,
  organizationId: string,
  ownerOpenId: string,
): Promise<{
  readonly ownerUserId: string;
  readonly feishuConnectionId: string;
  readonly appIdentityFingerprint: string;
} | null> {
  const organizations = await prisma.organization.findMany({
    take: 2,
    include: {
      memberships: {
        where: { role: "OWNER", revokedAt: null },
        take: 2,
        include: { user: { include: { feishuIdentities: true } } },
      },
      feishuApplicationConnection: true,
    },
  });
  if (organizations.length === 0) return null;
  if (organizations.length !== 1 || organizations[0]!.id !== organizationId) {
    throw new Error("bootstrap database is not the configured single-Organization Silo");
  }
  const organization = organizations[0]!;
  if (organization.status !== "ACTIVE" || organization.memberships.length !== 1 ||
      organization.feishuApplicationConnection?.status !== "ACTIVE") {
    throw new Error("existing Silo is incomplete or inactive; manual repair is required");
  }
  const ownerIdentity = organization.memberships[0]!.user.feishuIdentities.find(
    (identity) => identity.connectionId === organization.feishuApplicationConnection!.id,
  );
  if (ownerIdentity?.openId !== ownerOpenId) {
    throw new Error("bootstrap owner identity does not match the existing Silo");
  }
  return {
    ownerUserId: organization.memberships[0]!.userId,
    feishuConnectionId: organization.feishuApplicationConnection.id,
    appIdentityFingerprint: organization.feishuApplicationConnection.appIdentityFingerprint,
  };
}

async function loadExistingProviderCredential(
  prisma: PrismaClient,
  secrets: LocalSecretEnvelope,
  organizationId: string,
  providerId: string,
): Promise<{ readonly baseUrl: string; readonly authToken: string; readonly anthropicApiKey: string }> {
  const connection = await prisma.organizationProviderConnection.findUnique({
    where: { organizationId_providerId: { organizationId, providerId } },
    include: { activeSecretVersion: true },
  });
  const version = connection?.activeSecretVersion;
  if (connection === null || connection === undefined || version === null || version === undefined ||
      connection.status !== "ACTIVE" || version.retiredAt !== null) {
    throw new Error(`active provider connection not found: ${providerId}`);
  }
  return decryptStoredProviderCredential(secrets, {
    organizationId,
    connectionId: connection.id,
    providerId,
    secretVersionId: version.id,
    envelopeVersion: version.envelopeVersion,
    keyId: version.keyId,
    envelope: version.envelope,
  });
}

function validateInput(input: AlphaSiloBootstrapInput): AlphaSiloBootstrapInput {
  const required = (value: string, label: string): string => {
    const normalized = value.trim();
    if (normalized === "") throw new Error(`${label} is required`);
    return normalized;
  };
  const slug = required(input.organization.slug, "Organization slug");
  if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(slug)) {
    throw new Error("Organization slug must be lowercase alphanumeric with optional hyphens");
  }
  if (input.provider.providerId.trim() !== "openrouter") {
    throw new Error("Alpha Silo currently requires providerId=openrouter");
  }
  return {
    organization: {
      id: required(input.organization.id, "Organization id"),
      slug,
      name: required(input.organization.name, "Organization name"),
    },
    owner: {
      openId: required(input.owner.openId, "Owner Feishu openId"),
      displayName: required(input.owner.displayName, "Owner displayName"),
      ...(input.owner.unionId !== undefined ? { unionId: required(input.owner.unionId, "Owner unionId") } : {}),
    },
    feishu: input.feishu,
    provider: input.provider,
    ...(input.teams !== undefined
      ? {
          teams: input.teams.map((team) => {
            const teamSlug = required(team.slug, "Team slug");
            if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(teamSlug)) {
              throw new Error(`invalid Team slug: ${teamSlug}`);
            }
            return {
              slug: teamSlug,
              name: required(team.name, `Team ${teamSlug} name`),
              ...(team.description !== undefined ? { description: team.description.trim() } : {}),
            };
          }),
        }
      : {}),
  };
}
