// server/api/users/sync-all.post.ts
// Sync all users from Keycloak Admin API to database
// This endpoint will fetch all users from Keycloak and sync them to the database

import Database from 'better-sqlite3';
import { join } from 'path';
import { existsSync, mkdirSync } from 'fs';

// Helper to get database path
const getDbPath = () => {
  const dbDir = join(process.cwd(), 'data');
  if (!existsSync(dbDir)) {
    mkdirSync(dbDir, { recursive: true });
  }
  return join(dbDir, 'users.db');
};

// Helper to decode JWT token payload
const decodeTokenPayload = (token: string | undefined): any | null => {
  if (!token) return null;
  try {
    const parts = token.split(".");
    if (parts.length < 2) return null;
    const payloadBase64 = parts[1];
    return JSON.parse(Buffer.from(payloadBase64, "base64").toString());
  } catch (e) {
    return null;
  }
};

// Helper to get last access from Keycloak for a user
const getLastAccessFromKeycloak = async (userId: string, accessToken: string, config: any): Promise<number | null> => {
  try {
    if (!accessToken) {
      return null;
    }

    const issuerUrl = new URL(config.keycloakIssuer);
    const realm = issuerUrl.pathname.split('/').filter(Boolean).pop() || 'master';
    const sessionsUrl = `${config.keycloakIssuer.replace('/realms/' + realm, '')}/admin/realms/${realm}/users/${userId}/sessions`;
    
    const sessionsResponse = await fetch(sessionsUrl, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
      },
    });

    if (!sessionsResponse.ok) {
      return null;
    }

    const sessions = await sessionsResponse.json() as any[];
    if (!sessions || sessions.length === 0) {
      return null;
    }

    let lastAccessTimestamp = 0;
    sessions.forEach(session => {
      if (session.lastAccess && session.lastAccess > lastAccessTimestamp) {
        lastAccessTimestamp = session.lastAccess;
      }
    });

    return lastAccessTimestamp > 0 ? Math.floor(lastAccessTimestamp / 1000) : null;
  } catch (error: any) {
    console.warn(`⚠️ Error fetching last access for user ${userId}:`, error.message);
    return null;
  }
};

// Helper to get user from Keycloak Admin API
const getUserFromKeycloak = async (userId: string, accessToken: string, config: any): Promise<any | null> => {
  try {
    if (!accessToken) {
      return null;
    }

    const issuerUrl = new URL(config.keycloakIssuer);
    const realm = issuerUrl.pathname.split('/').filter(Boolean).pop() || 'master';
    const userUrl = `${config.keycloakIssuer.replace('/realms/' + realm, '')}/admin/realms/${realm}/users/${userId}`;
    
    const userResponse = await fetch(userUrl, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
      },
    });

    if (!userResponse.ok) {
      return null;
    }

    return await userResponse.json();
  } catch (error: any) {
    console.warn(`⚠️ Error fetching user ${userId} from Keycloak:`, error.message);
    return null;
  }
};

// Helper to get all users from Keycloak Admin API
const getAllUsersFromKeycloak = async (accessToken: string, config: any): Promise<any[]> => {
  try {
    if (!accessToken) {
      return [];
    }

    const issuerUrl = new URL(config.keycloakIssuer);
    const realm = issuerUrl.pathname.split('/').filter(Boolean).pop() || 'master';
    const usersUrl = `${config.keycloakIssuer.replace('/realms/' + realm, '')}/admin/realms/${realm}/users?max=1000`;
    
    const usersResponse = await fetch(usersUrl, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json',
      },
    });

    if (!usersResponse.ok) {
      console.warn('⚠️ Failed to fetch users from Keycloak:', usersResponse.status);
      return [];
    }

    return await usersResponse.json();
  } catch (error: any) {
    console.warn(`⚠️ Error fetching all users from Keycloak:`, error.message);
    return [];
  }
};

// Initialize database
const initDb = () => {
  const dbPath = getDbPath();
  const db = new Database(dbPath);
  
  // Create table if not exists
  db.exec(`
    CREATE TABLE IF NOT EXISTS users (
      id TEXT PRIMARY KEY,
      namaLengkap TEXT NOT NULL,
      namaUser TEXT UNIQUE NOT NULL,
      email TEXT,
      tipeUser TEXT DEFAULT '',
      lastLogin INTEGER,
      roles TEXT DEFAULT '[]',
      realmRoles TEXT DEFAULT '[]',
      accountRoles TEXT DEFAULT '[]',
      resourceRoles TEXT DEFAULT '[]',
      groups TEXT DEFAULT '[]',
      given_name TEXT,
      family_name TEXT,
      createdAt INTEGER DEFAULT (strftime('%s', 'now')),
      updatedAt INTEGER DEFAULT (strftime('%s', 'now'))
    )
  `);
  
  // Migration: Check and add missing columns one by one
  try {
    const tableInfo = db.prepare("PRAGMA table_info(users)").all() as any[];
    const columnNames = tableInfo.map(col => col.name);
    
    // Add missing columns one by one
    if (!columnNames.includes('realmRoles')) {
      db.exec(`ALTER TABLE users ADD COLUMN realmRoles TEXT DEFAULT '[]'`);
      console.log('✅ Added column: realmRoles');
    }
    
    if (!columnNames.includes('accountRoles')) {
      db.exec(`ALTER TABLE users ADD COLUMN accountRoles TEXT DEFAULT '[]'`);
      console.log('✅ Added column: accountRoles');
    }
    
    if (!columnNames.includes('resourceRoles')) {
      db.exec(`ALTER TABLE users ADD COLUMN resourceRoles TEXT DEFAULT '[]'`);
      console.log('✅ Added column: resourceRoles');
    }
    
    if (!columnNames.includes('lastLogin')) {
      db.exec(`ALTER TABLE users ADD COLUMN lastLogin INTEGER`);
      console.log('✅ Added column: lastLogin');
    }
    
    if (!columnNames.includes('given_name')) {
      db.exec(`ALTER TABLE users ADD COLUMN given_name TEXT`);
      console.log('✅ Added column: given_name');
    }
    
    if (!columnNames.includes('family_name')) {
      db.exec(`ALTER TABLE users ADD COLUMN family_name TEXT`);
      console.log('✅ Added column: family_name');
    }
  } catch (e: any) {
    console.error('❌ Migration error:', e.message);
    // Don't throw, continue with existing schema
  }
  
  return db;
};

export default defineEventHandler(async (event) => {
  console.log("🔄 Sync all users endpoint called");

  // Get session from session store
  const { getSessionFromCookie } = await import('~/server/utils/sessionStore');
  const session = await getSessionFromCookie(event);
  
  if (!session) {
    throw createError({
      statusCode: 401,
      statusMessage: "No session found or session expired",
    });
  }

  try {
    const config = useRuntimeConfig();
    const accessToken = session.accessToken;
    if (!accessToken) {
      throw createError({
        statusCode: 401,
        statusMessage: "No access token found",
      });
    }

    // Get all users from Keycloak
    console.log("📥 Fetching all users from Keycloak...");
    const keycloakUsers = await getAllUsersFromKeycloak(accessToken, config);
    console.log(`✅ Found ${keycloakUsers.length} users in Keycloak`);

    const db = initDb();
    let createdCount = 0;
    let updatedCount = 0;
    let unchangedCount = 0;

    // Sync each user
    for (const kcUser of keycloakUsers) {
      try {
        const userId = kcUser.id;
        const namaLengkap = kcUser.firstName && kcUser.lastName 
          ? `${kcUser.firstName} ${kcUser.lastName}`.trim()
          : kcUser.firstName || kcUser.lastName || kcUser.username || '';
        const namaUser = kcUser.username || kcUser.email?.split('@')[0] || '';
        const email = kcUser.email || null;
        const given_name = kcUser.firstName || null;
        const family_name = kcUser.lastName || null;

        if (!userId || !namaUser) {
          console.warn(`⚠️ Skipping user with missing ID or username: ${userId}`);
          continue;
        }

        // Get user details from Keycloak (including roles and groups)
        const userDetails = await getUserFromKeycloak(userId, accessToken, config);
        
        // Extract roles and groups
        const realmRoles = userDetails?.realmRoles || [];
        const groups = userDetails?.groups || [];
        
        // Determine tipeUser from groups
        let tipeUser = '';
        if (Array.isArray(groups) && groups.length > 0) {
          const lastGroup = groups[groups.length - 1];
          if (typeof lastGroup === 'string') {
            const parts = lastGroup.split('/').filter(Boolean);
            if (parts.length > 0) {
              tipeUser = parts[parts.length - 1];
            }
          }
        }

        // Get last access from Keycloak
        const lastLogin = await getLastAccessFromKeycloak(userId, accessToken, config);

        // Check if user exists in database
        const existingUser = db.prepare('SELECT * FROM users WHERE id = ?').get(userId) as any;

        const rolesJson = JSON.stringify(realmRoles);
        const realmRolesJson = JSON.stringify(realmRoles);
        const accountRolesJson = JSON.stringify([]);
        const resourceRolesJson = JSON.stringify([]);
        const groupsJson = JSON.stringify(groups);

        if (existingUser) {
          // Update existing user - only update if there are changes
          const needsUpdate = 
            existingUser.namaLengkap !== namaLengkap ||
            existingUser.namaUser !== namaUser ||
            existingUser.email !== email ||
            existingUser.roles !== rolesJson ||
            existingUser.realmRoles !== realmRolesJson ||
            existingUser.groups !== groupsJson ||
            existingUser.given_name !== given_name ||
            existingUser.family_name !== family_name ||
            (existingUser.tipeUser === '' && tipeUser !== '') ||
            (lastLogin && existingUser.lastLogin !== lastLogin);

          if (needsUpdate) {
            const updateTipeUser = existingUser.tipeUser === '' ? tipeUser : existingUser.tipeUser;
            const updateLastLogin = lastLogin || existingUser.lastLogin;

            db.prepare(`
              UPDATE users 
              SET namaLengkap = ?,
                  namaUser = ?,
                  email = ?,
                  roles = ?,
                  realmRoles = ?,
                  accountRoles = ?,
                  resourceRoles = ?,
                  groups = ?,
                  given_name = ?,
                  family_name = ?,
                  tipeUser = ?,
                  lastLogin = ?,
                  updatedAt = strftime('%s', 'now')
              WHERE id = ?
            `).run(
              namaLengkap,
              namaUser,
              email || null,
              rolesJson,
              realmRolesJson,
              accountRolesJson,
              resourceRolesJson,
              groupsJson,
              given_name,
              family_name,
              updateTipeUser,
              updateLastLogin,
              userId
            );
            updatedCount++;
            console.log(`✅ Updated user: ${namaUser}`);
          } else {
            unchangedCount++;
          }
        } else {
          // Insert new user
          db.prepare(`
            INSERT INTO users (
              id, namaLengkap, namaUser, email, roles, realmRoles, accountRoles, resourceRoles, groups, 
              given_name, family_name, tipeUser, lastLogin
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
          `).run(
            userId,
            namaLengkap,
            namaUser,
            email || null,
            rolesJson,
            realmRolesJson,
            accountRolesJson,
            resourceRolesJson,
            groupsJson,
            given_name,
            family_name,
            tipeUser,
            lastLogin
          );
          createdCount++;
          console.log(`✅ Created new user: ${namaUser}`);
        }
      } catch (userError: any) {
        console.error(`❌ Error syncing user ${kcUser.id}:`, userError.message);
        // Continue with next user
      }
    }

    db.close();

    console.log(`✅ Sync completed: ${createdCount} created, ${updatedCount} updated, ${unchangedCount} unchanged`);
    
    return {
      success: true,
      message: 'All users synced successfully',
      stats: {
        created: createdCount,
        updated: updatedCount,
        unchanged: unchangedCount,
        total: keycloakUsers.length
      }
    };
  } catch (error: any) {
    console.error("❌ Error syncing all users:", error);
    throw createError({
      statusCode: 500,
      statusMessage: error.message || "Failed to sync all users",
    });
  }
});

