import { writeFileSync } from 'node:fs';
import { and, eq, isNull } from 'drizzle-orm';
import { crmRoleProfiles, crmUserRoleAssignments, memberships } from '@/db/schema';
import { auditAction } from '@/features/foundation/audit-log/service';
import { db } from '@/lib/db';

type MigrationReport = {
  mode: 'dry-run' | 'execute';
  startedAt: string;
  completedAt?: string;
  migratedUsers: number;
  skippedUsers: number;
  unknownRoles: Array<{ membershipId: string; organizationId: string; userId: string; businessRole: string }>;
  duplicateAssignments: Array<{ membershipId: string; assignmentId: string; organizationId: string; userId: string }>;
  actions: Array<Record<string, unknown>>;
};

function getArg(name: string) {
  const match = process.argv.find((arg) => arg === name || arg.startsWith(`${name}=`));

  if (!match) {
    return null;
  }

  if (match === name) {
    return 'true';
  }

  return match.slice(name.length + 1);
}

async function main() {
  const execute = getArg('--execute') === 'true';
  const reportPath = getArg('--report');
  const snapshotPath = getArg('--snapshot');
  const report: MigrationReport = {
    mode: execute ? 'execute' : 'dry-run',
    startedAt: new Date().toISOString(),
    migratedUsers: 0,
    skippedUsers: 0,
    unknownRoles: [],
    duplicateAssignments: [],
    actions: []
  };

  const membershipRows = await db.query.memberships.findMany();

  if (snapshotPath) {
    writeFileSync(snapshotPath, JSON.stringify(membershipRows, null, 2));
  }

  for (const membership of membershipRows) {
    const [roleProfile] = await db
      .select({
        id: crmRoleProfiles.id
      })
      .from(crmRoleProfiles)
      .where(
        and(
          eq(crmRoleProfiles.organizationId, membership.organizationId),
          eq(crmRoleProfiles.code, membership.businessRole),
          isNull(crmRoleProfiles.deletedAt)
        )
      )
      .limit(1);

    if (!roleProfile) {
      report.skippedUsers += 1;
      report.unknownRoles.push({
        membershipId: membership.id,
        organizationId: membership.organizationId,
        userId: membership.userId,
        businessRole: membership.businessRole
      });
      continue;
    }

    const existing = await db.query.crmUserRoleAssignments.findFirst({
      where: and(
        eq(crmUserRoleAssignments.organizationId, membership.organizationId),
        eq(crmUserRoleAssignments.userId, membership.userId),
        eq(crmUserRoleAssignments.roleProfileId, roleProfile.id)
      )
    });

    if (existing && !existing.deletedAt) {
      report.skippedUsers += 1;
      report.duplicateAssignments.push({
        membershipId: membership.id,
        assignmentId: existing.id,
        organizationId: membership.organizationId,
        userId: membership.userId
      });
      continue;
    }

    const actionPayload = {
      membershipId: membership.id,
      organizationId: membership.organizationId,
      userId: membership.userId,
      roleProfileId: roleProfile.id,
      businessRole: membership.businessRole,
      branchScopeIds: membership.branchScopeIds ?? [],
      productTypeScopeIds: membership.productTypeScopeIds ?? []
    };

    report.actions.push(actionPayload);
    report.migratedUsers += 1;

    if (!execute) {
      continue;
    }

    const assignmentId = existing?.id ?? crypto.randomUUID();

    if (existing) {
      await db
        .update(crmUserRoleAssignments)
        .set({
          branchScopeMode: (membership.branchScopeIds?.length ?? 0) > 0 ? 'selected' : 'all',
          branchScopeIds: membership.branchScopeIds ?? [],
          productTypeScopeMode:
            (membership.productTypeScopeIds?.length ?? 0) > 0 ? 'selected' : 'all',
          productTypeScopeIds: membership.productTypeScopeIds ?? [],
          isPrimary: true,
          isActive: true,
          assignedBy: 'system:migration',
          assignedAt: new Date(),
          updatedAt: new Date(),
          deletedAt: null
        })
        .where(eq(crmUserRoleAssignments.id, existing.id));
    } else {
      await db.insert(crmUserRoleAssignments).values({
        id: assignmentId,
        organizationId: membership.organizationId,
        userId: membership.userId,
        roleProfileId: roleProfile.id,
        branchScopeMode: (membership.branchScopeIds?.length ?? 0) > 0 ? 'selected' : 'all',
        branchScopeIds: membership.branchScopeIds ?? [],
        productTypeScopeMode:
          (membership.productTypeScopeIds?.length ?? 0) > 0 ? 'selected' : 'all',
        productTypeScopeIds: membership.productTypeScopeIds ?? [],
        isPrimary: true,
        isActive: true,
        assignedBy: 'system:migration'
      });
    }

    await auditAction({
      organizationId: membership.organizationId,
      userId: 'system:migration',
      entityType: 'crm_user_role_assignment',
      entityId: assignmentId,
      action: 'migrate',
      afterData: actionPayload
    });
  }

  report.completedAt = new Date().toISOString();

  if (reportPath) {
    writeFileSync(reportPath, JSON.stringify(report, null, 2));
  }

  console.info(JSON.stringify(report, null, 2));
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
