import { createHash, randomUUID } from 'node:crypto';
import bcrypt from 'bcryptjs';
import { Router } from 'express';
import { z } from 'zod';
import { requireAdmin, requireAuth, type AuthenticatedRequest } from './auth';
import { config } from './config';
import { pool } from './db';
import { listLiveKitParticipants, listLiveKitRooms, removeLiveKitParticipant } from './liveKitMedia';
import { profileFields, profileSchema } from './sharedJourney';
import { generateAvailableUsername } from './usernames';
import { deleteAccountImmediately } from './accountLifecycle';

export const adminUsersRouter = Router();

const accountUpdateSchema = z.object({
  displayName: z.string().trim().min(2).max(80),
  email: z.email().max(254).optional(),
  username: z.string().trim().toLowerCase().regex(/^[a-z][a-z0-9_-]{3,29}$/).optional(),
});

const passwordSchema = z.object({ password: z.string().min(10).max(128) });
const deleteSchema = z.object({ confirmed: z.literal(true) });
const createUserSchema = z.object({
  displayName: z.string().trim().min(2).max(80),
  email: z.email().max(254),
  password: z.string().min(10).max(128),
  role: z.enum(['admin', 'user', 'guardian']).default('user'),
  linkedCandidateId: z.uuid().optional(),
});

adminUsersRouter.post('/users', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const parsed = createUserSchema.safeParse(request.body);
  if (!parsed.success) { response.status(400).json({ error: 'Invalid user data' }); return; }
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    if (parsed.data.role === 'guardian' && parsed.data.linkedCandidateId) {
      const candidate = await client.query(
        `SELECT 1 FROM users WHERE id=$1 AND role='user' AND account_type='candidate'
         AND is_active AND deleted_at IS NULL FOR UPDATE`, [parsed.data.linkedCandidateId],
      );
      if (!candidate.rowCount) {
        await client.query('ROLLBACK'); response.status(404).json({ error: 'Linked candidate not found' }); return;
      }
      const existing = await client.query(
        "SELECT 1 FROM guardian_invitations WHERE candidate_user_id=$1 AND status='verified'",
        [parsed.data.linkedCandidateId],
      );
      if (existing.rowCount) {
        await client.query('ROLLBACK'); response.status(409).json({ error: 'Candidate already has a verified guardian' }); return;
      }
    }
    const username = await generateAvailableUsername(client, parsed.data.displayName);
    const passwordHash = await bcrypt.hash(parsed.data.password, 12);
    const userId = randomUUID();
    const databaseRole = parsed.data.role === 'admin' ? 'admin' : 'user';
    const accountType = parsed.data.role === 'guardian' ? 'guardian' : 'candidate';
    const result = await client.query(
      `INSERT INTO users (id,email,password_hash,display_name,username,role,account_type)
       VALUES ($1,$2,$3,$4,$5,$6,$7)
       RETURNING id,email,display_name AS "displayName",username,role,account_type AS "accountType"`,
      [userId, parsed.data.email.toLowerCase(), passwordHash, parsed.data.displayName, username,
        databaseRole, accountType],
    );
    if (databaseRole === 'user' && accountType === 'candidate') {
      await client.query('INSERT INTO profiles (user_id,display_name) VALUES ($1,$2)',
        [result.rows[0].id, parsed.data.displayName]);
    }
    if (accountType === 'guardian' && parsed.data.linkedCandidateId) {
      await client.query(
        "UPDATE guardian_invitations SET status='revoked',completed_at=NOW() WHERE candidate_user_id=$1 AND status IN ('pending','registered')",
        [parsed.data.linkedCandidateId],
      );
      const invitationId = randomUUID();
      const codeHash = createHash('sha256').update(randomUUID()).digest('hex');
      await client.query(
        `INSERT INTO guardian_invitations
           (id,candidate_user_id,code_hash,status,accepted_by,expires_at,completed_at,
            admin_note,reviewed_by,reviewed_at,contact_confirmed_at)
         VALUES ($1,$2,$3,'verified',$4,NOW()+INTERVAL '15 minutes',NOW(),
           'Linked directly by an administrator',$5,NOW(),NOW())`,
        [invitationId, parsed.data.linkedCandidateId, codeHash, userId, request.authUser!.id],
      );
    }
    await client.query(
      "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_user_created',$2::jsonb)",
      [request.authUser!.id, JSON.stringify({ targetUserId: result.rows[0].id,
        createdRole: parsed.data.role, linkedCandidateId: parsed.data.linkedCandidateId ?? null })],
    );
    await client.query('COMMIT');
    response.status(201).json({ user: result.rows[0] });
  } catch (error) {
    await client.query('ROLLBACK');
    if (typeof error === 'object' && error !== null && 'code' in error && error.code === '23505') {
      response.status(409).json({ error: 'Email is already registered' }); return;
    }
    throw error;
  } finally { client.release(); }
});

adminUsersRouter.get('/overview', requireAuth, requireAdmin, async (_request, response) => {
  const [users, events, stats] = await Promise.all([
    pool.query(
      `SELECT u.id, u.email,
              u.username, u.account_type AS "accountType", u.display_name AS "displayName",
              u.role, u.is_active AS "isActive", u.created_at AS "createdAt",
              u.deleted_at AS "deletedAt",u.purge_after AS "purgeAfter",
              p.approval_status AS "profileStatus",
              p.identity_status AS "identityStatus",
              COALESCE(p.publication_requested, FALSE) AS "profileCompleted",
              COALESCE(guardian_links.members, '[]'::jsonb) AS "linkedMembers"
       FROM users u
       LEFT JOIN profiles p ON p.user_id=u.id
       LEFT JOIN LATERAL (
         SELECT jsonb_agg(jsonb_build_object(
           'id', family_link.id, 'displayName', family_link.display_name,
           'username', family_link.username, 'status', family_link.status
         ) ORDER BY family_link.created_at DESC) AS members
         FROM (
           SELECT candidate.id,candidate.display_name,candidate.username,
                  invitation.status,invitation.created_at
           FROM guardian_invitations invitation
           JOIN users candidate ON candidate.id=invitation.candidate_user_id
           WHERE invitation.accepted_by=u.id AND invitation.status IN ('registered','verified')
           UNION ALL
           SELECT candidate.id,candidate.display_name,candidate.username,
                  CASE WHEN exception.status='approved' THEN 'verified' ELSE 'registered' END,
                  exception.created_at
           FROM guardian_exceptions exception
           JOIN users candidate ON candidate.id=exception.candidate_user_id
           WHERE exception.representative_user_id=u.id AND exception.status IN ('pending','approved')
         ) family_link
       ) guardian_links ON TRUE
       ORDER BY u.created_at DESC`,
    ),
    pool.query(
      `SELECT e.id, e.event_type AS "eventType", e.details, e.created_at AS "createdAt",
              u.email, u.display_name AS "displayName"
       FROM audit_events e LEFT JOIN users u ON u.id=e.user_id
       ORDER BY e.created_at DESC LIMIT 100`,
    ),
    pool.query(
      `SELECT COUNT(*)::int AS "userCount",
              COUNT(*) FILTER (WHERE role='user' AND is_active)::int AS "activeUserCount",
              COUNT(*) FILTER (WHERE role='admin')::int AS "adminCount"
       FROM users`,
    ),
  ]);
  response.json({ users: users.rows, events: events.rows, stats: stats.rows[0] });
});

adminUsersRouter.get('/users/:id/journeys', requireAuth, requireAdmin, async (request, response) => {
  const targetId = z.uuid().safeParse(request.params.id);
  if (!targetId.success) { response.status(400).json({ error: 'Invalid user ID' }); return; }
  const target = await pool.query('SELECT 1 FROM users WHERE id=$1', [targetId.data]);
  if (!target.rowCount) { response.status(404).json({ error: 'User not found' }); return; }
  const journeys = await pool.query<{
    id: string; status: 'active' | 'closed'; createdAt: Date;
    firstUserId: string; secondUserId: string; requestId: string; firstName: string; secondName: string;
    relation: 'participant' | 'guardian'; meetingId: string | null; meetingStatus: string | null;
    startsAt: Date | null; sessionNumber: number | null; proposedBy: string | null;
    confirmationCount: number; paymentsReady: boolean; activeParticipantCount: number;
    targetHasPhoto: boolean; targetPhotoSharingStatus: string | null;
    counterpartHasPhoto: boolean; counterpartPhotoAccessStatus: string | null;
    incomingPhotoRequest: boolean; certificateFileName: string | null; certificateExpiresAt: Date | null;
  }>(
    `SELECT DISTINCT j.id,j.status,j.created_at AS "createdAt",
       j.first_user_id AS "firstUserId",j.second_user_id AS "secondUserId",j.request_id AS "requestId",
       first_user.display_name AS "firstName",second_user.display_name AS "secondName",
       CASE WHEN $1 IN (j.first_user_id,j.second_user_id) THEN 'participant' ELSE 'guardian' END AS relation,
       meeting.id AS "meetingId",meeting.status AS "meetingStatus",meeting.starts_at AS "startsAt",
       meeting.session_number AS "sessionNumber",meeting.proposed_by AS "proposedBy",
       CASE WHEN meeting.status IN ('confirmed','completed') THEN
         2+(SELECT COUNT(*)::int FROM meeting_schedule_confirmations confirmation
            WHERE confirmation.meeting_id=meeting.id)
         WHEN meeting.status='proposed' THEN 1 ELSE 0 END AS "confirmationCount",
       EXISTS (SELECT 1 FROM meeting_payment_obligations payment
         WHERE payment.meeting_id=meeting.id AND payment.status='paid') AS "paymentsReady",
       (SELECT COUNT(*)::int FROM meeting_call_sessions session WHERE session.meeting_id=meeting.id
         AND session.left_at IS NULL AND session.last_seen_at>=NOW()-INTERVAL '30 seconds') AS "activeParticipantCount",
       EXISTS (SELECT 1 FROM profile_photos photo WHERE photo.user_id=$1) AS "targetHasPhoto",
       (SELECT access.status FROM profile_photo_access access
         WHERE access.owner_user_id=$1
           AND access.viewer_user_id=CASE WHEN j.first_user_id=$1 THEN j.second_user_id ELSE j.first_user_id END)
         AS "targetPhotoSharingStatus",
       EXISTS (SELECT 1 FROM profile_photos photo
         WHERE photo.user_id=CASE WHEN j.first_user_id=$1 THEN j.second_user_id ELSE j.first_user_id END)
         AS "counterpartHasPhoto",
       (SELECT access.status FROM profile_photo_access access
         WHERE access.owner_user_id=CASE WHEN j.first_user_id=$1 THEN j.second_user_id ELSE j.first_user_id END
           AND access.viewer_user_id=$1) AS "counterpartPhotoAccessStatus",
       EXISTS (SELECT 1 FROM profile_photo_access access
         WHERE access.owner_user_id=$1
           AND access.viewer_user_id=CASE WHEN j.first_user_id=$1 THEN j.second_user_id ELSE j.first_user_id END
           AND access.status='requested') AS "incomingPhotoRequest",
       certificate.file_name AS "certificateFileName",certificate.expires_at AS "certificateExpiresAt"
     FROM journeys j
     JOIN users first_user ON first_user.id=j.first_user_id
     JOIN users second_user ON second_user.id=j.second_user_id
     LEFT JOIN journey_memberships membership ON membership.journey_id=j.id AND membership.user_id=$1
     LEFT JOIN LATERAL (SELECT proposal.* FROM meeting_proposals proposal
       WHERE proposal.journey_id=j.id ORDER BY proposal.created_at DESC LIMIT 1) meeting ON TRUE
     LEFT JOIN journey_certificates certificate ON certificate.journey_id=j.id AND certificate.expires_at>NOW()
     WHERE $1 IN (j.first_user_id,j.second_user_id) OR membership.user_id IS NOT NULL
     ORDER BY j.created_at DESC`, [targetId.data],
  );
  const journeyIds = journeys.rows.map((item) => item.id);
  const requestIds = journeys.rows.map((item) => item.requestId);
  const events = journeyIds.length ? await pool.query<{
    id: number; journeyId: string | null; requestId: string; type: string; actorName: string | null;
    details: Record<string, unknown>; createdAt: Date;
  }>(
    `SELECT event.id,event.journey_id AS "journeyId",event.event_type AS type,
       event.request_id AS "requestId",actor.display_name AS "actorName",
       CASE WHEN event.event_type='meeting_completed' AND event.details ? 'meetingId'
         THEN event.details || jsonb_build_object('durationSeconds',COALESCE((
           SELECT GREATEST(0,EXTRACT(EPOCH FROM
             (MAX(COALESCE(session.left_at,session.last_seen_at))-MIN(session.joined_at))))::int
           FROM meeting_call_sessions session
           WHERE session.meeting_id::text=event.details->>'meetingId'),0))
         ELSE event.details END AS details,event.created_at AS "createdAt"
     FROM relationship_events event LEFT JOIN users actor ON actor.id=event.actor_user_id
     WHERE event.journey_id=ANY($1::uuid[]) OR event.request_id=ANY($2::uuid[])
     ORDER BY event.created_at,event.id`, [journeyIds, requestIds],
  ) : { rows: [] };
  response.json({ journeys: journeys.rows.map((journey) => ({
    ...journey,
    events: events.rows.filter((event) => event.journeyId === journey.id
      || event.requestId === journey.requestId),
  })) });
});

adminUsersRouter.get('/users/:id/profile', requireAuth, requireAdmin, async (request, response) => {
  const target = await pool.query<{ display_name: string }>(
    "SELECT display_name FROM users WHERE id=$1 AND role='user' AND account_type='candidate'",
    [request.params.id],
  );
  if (!target.rows[0]) { response.status(404).json({ error: 'Profile account not found' }); return; }
  await pool.query(
    'INSERT INTO profiles (user_id,display_name) VALUES ($1,$2) ON CONFLICT (user_id) DO NOTHING',
    [request.params.id, target.rows[0].display_name],
  );
  const result = await pool.query(
    `SELECT ${profileFields},p.review_note AS "reviewNote" FROM profiles p WHERE p.user_id=$1`,
    [request.params.id],
  );
  response.json({ profile: result.rows[0] });
});

adminUsersRouter.patch('/users/:id/profile', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const parsed = profileSchema.safeParse(request.body);
  if (!parsed.success) { response.status(400).json({ error: 'Invalid profile data' }); return; }
  const value = {
    ...parsed.data,
    city: parsed.data.country,
    preferredGender: parsed.data.gender === 'man' ? 'woman' as const : 'man' as const,
    preferredReligion: parsed.data.religion,
  };
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const currentResult = await client.query<Record<string, unknown>>(
      `SELECT ${profileFields} FROM profiles p JOIN users u ON u.id=p.user_id
       WHERE p.user_id=$1 AND u.role='user' AND u.account_type='candidate' FOR UPDATE OF p`,
      [request.params.id],
    );
    const current = currentResult.rows[0];
    if (!current) { await client.query('ROLLBACK'); response.status(404).json({ error: 'Profile not found' }); return; }
    if (current.version !== value.expectedVersion) {
      await client.query('ROLLBACK'); response.status(409).json({ error: 'Profile version conflict' }); return;
    }
    const changedFields = Object.keys(value).filter((field) => field !== 'expectedVersion'
      && current[field] !== value[field as keyof typeof value]);
    const updated = await client.query(
      `UPDATE profiles p SET display_name=$1,gender=$2,birth_year=$3,birth_place=$4,country=$5,city=$6,
         marital_status=$7,children_count=$8,has_children=($8::integer>0),education=$9,occupation=$10,
         bio=$11,values_text=$12,partner_description=$13,skin_tone=$14,eye_color=$15,hair_color=$16,
         height_cm=$17,weight_kg=$18,body_build=$19,appearance_note=$20,preferred_gender=$21,
         preferred_min_age=$22,preferred_max_age=$23,preferred_country=$24,
         preferred_marital_status=$25,preferred_education=$26,accepts_partner_children=$27,
         preferred_max_children=$28,is_complete=TRUE,publication_requested=TRUE,
         religion=$29,preferred_religion=$30,
         preferred_eye_colors=$31,preferred_hair_colors=$32,music_preferences=$33,
         is_published=TRUE,approval_status='approved',
         reviewed_by=NULL,reviewed_at=NULL,review_note='',version=version+1,updated_at=NOW()
       WHERE p.user_id=$34 AND p.version=$35
       RETURNING ${profileFields},p.review_note AS "reviewNote"`,
      [value.displayName, value.gender, value.birthYear, value.birthPlace, value.country, value.city,
        value.maritalStatus, value.childrenCount, value.education, value.occupation, value.bio,
        value.valuesText, value.partnerDescription, value.skinTone, value.eyeColor, value.hairColor,
        value.heightCm, value.weightKg, value.bodyBuild, value.appearanceNote, value.preferredGender,
        value.preferredMinAge, value.preferredMaxAge, value.preferredCountry,
        value.preferredMaritalStatus, value.preferredEducation, value.acceptsPartnerChildren,
        value.preferredMaxChildren, value.religion, value.preferredReligion,
        value.preferredEyeColors, value.preferredHairColors, value.musicPreferences,
        request.params.id, value.expectedVersion],
    );
    await client.query('UPDATE users SET display_name=$1 WHERE id=$2', [value.displayName, request.params.id]);
    await client.query(
      "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_profile_updated',$2::jsonb)",
      [request.authUser!.id, JSON.stringify({ targetUserId: request.params.id,
        version: updated.rows[0].version, changedFields })],
    );
    await client.query('COMMIT');
    response.json({ profile: updated.rows[0] });
  } catch (error) { await client.query('ROLLBACK'); throw error; }
  finally { client.release(); }
});

adminUsersRouter.patch('/users/:id', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const parsed = accountUpdateSchema.safeParse(request.body);
  if (!parsed.success) { response.status(400).json({ error: 'Invalid account data' }); return; }
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const target = await client.query('SELECT id FROM users WHERE id=$1 FOR UPDATE', [request.params.id]);
    if (!target.rows[0]) { await client.query('ROLLBACK'); response.status(404).json({ error: 'User not found' }); return; }
    if (!parsed.data.email || !parsed.data.username) {
      await client.query('ROLLBACK'); response.status(400).json({ error: 'Email and username are required' }); return;
    }
    const result = await client.query(
      `UPDATE users SET display_name=$1,email=$2,username=$3
       WHERE id=$4 RETURNING id,display_name AS "displayName",email,username`,
      [parsed.data.displayName, parsed.data.email?.toLowerCase(), parsed.data.username, request.params.id],
    );
    await client.query('UPDATE profiles SET display_name=$1 WHERE user_id=$2', [parsed.data.displayName, request.params.id]);
    await client.query(
      "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_user_account_updated',$2::jsonb)",
      [request.authUser!.id, JSON.stringify({ targetUserId: request.params.id })],
    );
    await client.query('COMMIT');
    response.json({ user: result.rows[0] });
  } catch (error) {
    await client.query('ROLLBACK');
    if (typeof error === 'object' && error !== null && 'code' in error && error.code === '23505') {
      response.status(409).json({ error: 'Email or username is already registered' }); return;
    }
    throw error;
  } finally { client.release(); }
});

adminUsersRouter.patch('/users/:id/password', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const parsed = passwordSchema.safeParse(request.body);
  if (!parsed.success) { response.status(400).json({ error: 'Invalid password' }); return; }
  const passwordHash = await bcrypt.hash(parsed.data.password, 12);
  const result = await pool.query(
    `UPDATE users SET password_hash=$1,token_version=token_version+1
     WHERE id=$2 RETURNING id`,
    [passwordHash, request.params.id],
  );
  if (!result.rowCount) { response.status(404).json({ error: 'Password account not found' }); return; }
  await pool.query(
    "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_user_password_reset',$2::jsonb)",
    [request.authUser!.id, JSON.stringify({ targetUserId: request.params.id })],
  );
  response.json({ changed: true });
});

adminUsersRouter.patch('/users/:id/status', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const parsed = z.object({ isActive: z.boolean() }).safeParse(request.body);
  if (!parsed.success) { response.status(400).json({ error: 'Invalid status' }); return; }
  if (!parsed.data.isActive && request.params.id === request.authUser!.id) {
    response.status(409).json({ error: 'An administrator cannot suspend their own account' }); return;
  }
  const target = await pool.query<{ role: 'user' | 'admin' }>('SELECT role FROM users WHERE id=$1', [request.params.id]);
  if (!target.rows[0]) { response.status(404).json({ error: 'User not found' }); return; }
  if (!parsed.data.isActive && target.rows[0].role === 'admin') {
    const remaining = await pool.query<{ count: number }>(
      "SELECT COUNT(*)::int AS count FROM users WHERE role='admin' AND is_active AND id<>$1", [request.params.id],
    );
    if (remaining.rows[0].count < 1) {
      response.status(409).json({ error: 'At least one active administrator is required' }); return;
    }
  }
  const result = await pool.query(
    `UPDATE users SET is_active=$1,token_version=token_version+1
     WHERE id=$2 AND deleted_at IS NULL
     RETURNING id,email,is_active AS "isActive"`, [parsed.data.isActive, request.params.id],
  );
  if (!result.rowCount) { response.status(404).json({ error: 'User not found' }); return; }
  await pool.query(
    "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_user_status_changed',$2::jsonb)",
    [request.authUser!.id, JSON.stringify({ targetUserId: request.params.id, isActive: parsed.data.isActive })],
  );
  response.json({ user: result.rows[0] });
});

adminUsersRouter.patch('/users/:id/identity', requireAuth, requireAdmin,
  async (request: AuthenticatedRequest, response) => {
    const parsed = z.object({
      status: z.enum(['unverified', 'reviewing', 'verified']),
      note: z.string().trim().max(1000),
    }).safeParse(request.body);
    if (!parsed.success) { response.status(400).json({ error: 'Invalid identity status' }); return; }
    const result = await pool.query(
      `UPDATE profiles SET identity_status=$1,identity_note=$2,updated_at=NOW()
       WHERE user_id=$3 RETURNING identity_status AS "identityStatus",identity_note AS "identityNote"`,
      [parsed.data.status, parsed.data.note, request.params.id],
    );
    if (!result.rowCount) { response.status(404).json({ error: 'Profile not found' }); return; }
    await pool.query(
      "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_identity_status_changed',$2::jsonb)",
      [request.authUser!.id, JSON.stringify({ targetUserId: request.params.id, status: parsed.data.status })],
    );
    response.json({ identity: result.rows[0] });
  });

const disconnectLiveKitUser = async (userId: string): Promise<void> => {
  if (!config.liveKit.configured) return;
  const rooms = await listLiveKitRooms();
  await Promise.all(rooms.map(async (room) => {
    const participants = await listLiveKitParticipants(room.name);
    await Promise.all(participants.filter((item) => item.identity.startsWith(`${userId}:`))
      .map((item) => removeLiveKitParticipant(room.name, item.identity)));
  }));
};

adminUsersRouter.delete('/users/:id', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const parsed = deleteSchema.safeParse(request.body);
  if (!parsed.success) {
    response.status(400).json({ error: 'Deletion confirmation is required' }); return;
  }
  const targetId = z.uuid().safeParse(request.params.id);
  if (!targetId.success) { response.status(400).json({ error: 'Invalid user ID' }); return; }
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const target = await client.query<{ role: 'user' | 'admin'; email: string | null }>(
      'SELECT role,email FROM users WHERE id=$1 FOR UPDATE', [targetId.data],
    );
    if (!target.rows[0]) { await client.query('ROLLBACK'); response.status(404).json({ error: 'User not found' }); return; }
    if (target.rows[0].role === 'admin') {
      if (targetId.data === request.authUser!.id) {
        await client.query('ROLLBACK'); response.status(409).json({ error: 'An administrator cannot delete their own account' }); return;
      }
      const remaining = await client.query<{ count: number }>(
        "SELECT COUNT(*)::int AS count FROM users WHERE role='admin' AND is_active AND id<>$1", [targetId.data],
      );
      if (remaining.rows[0].count < 1) {
        await client.query('ROLLBACK'); response.status(409).json({ error: 'At least one active administrator is required' }); return;
      }
      await client.query('DELETE FROM users WHERE id=$1', [targetId.data]);
      await client.query(
        "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_user_deleted',$2::jsonb)",
        [request.authUser!.id, JSON.stringify({ targetUserId: targetId.data,
          targetEmail: target.rows[0].email, accountType: 'admin' })],
      );
      await client.query('COMMIT');
      response.json({ deleted: true, linkedGuardianAccountsDeleted: 0 }); return;
    }
    const deletion = await deleteAccountImmediately(client, targetId.data, request.authUser!.id);
    if (!deletion) { await client.query('ROLLBACK'); response.status(404).json({ error: 'User not found' }); return; }
    await client.query(
      "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'admin_user_deleted',$2::jsonb)",
      [request.authUser!.id, JSON.stringify({
        targetUserId: targetId.data,
        accountType: deletion.accountType,
        targetEmail: deletion.targetEmail,
        linkedGuardianUserIds: deletion.guardianUserIds,
      })],
    );
    await client.query('COMMIT');
    await Promise.all(deletion.affectedUserIds.map(disconnectLiveKitUser));
    response.json({
      deleted: true,
      linkedGuardianAccountsDeleted: deletion.guardianUserIds.length,
    });
  } catch (error) { await client.query('ROLLBACK'); throw error; }
  finally { client.release(); }
});
