import * as plugins from '../../plugins.js';
import type { OpsServer } from '../classes.opsserver.js';
import * as interfaces from '../../../ts_interfaces/index.js';
import { requireOpsAuth } from '../helpers/auth.js';

export class TargetProfileHandler {
  public typedrouter = new plugins.typedrequest.TypedRouter();

  constructor(private opsServerRef: OpsServer) {
    this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
    this.registerHandlers();
  }

  private async requireAuth(
    request: { identity?: interfaces.data.IIdentity; apiToken?: string },
    requiredScope?: interfaces.data.TApiTokenScope,
  ): Promise<string> {
    const auth = await requireOpsAuth(this.opsServerRef, request, {
      scope: requiredScope,
      requireAdminIdentity: requiredScope?.endsWith(':write'),
    });
    return auth.userId;
  }

  private registerHandlers(): void {
    // Get all target profiles
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetTargetProfiles>(
        'getTargetProfiles',
        async (dataArg) => {
          await this.requireAuth(dataArg, 'target-profiles:read');
          const manager = this.opsServerRef.dcRouterRef.targetProfileManager;
          if (!manager) {
            return { profiles: [] };
          }
          return { profiles: manager.listProfiles() };
        },
      ),
    );

    // Get a single target profile
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetTargetProfile>(
        'getTargetProfile',
        async (dataArg) => {
          await this.requireAuth(dataArg, 'target-profiles:read');
          const manager = this.opsServerRef.dcRouterRef.targetProfileManager;
          if (!manager) {
            return { profile: null };
          }
          return { profile: manager.getProfile(dataArg.id) || null };
        },
      ),
    );

    // Create a target profile
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateTargetProfile>(
        'createTargetProfile',
        async (dataArg) => {
          const userId = await this.requireAuth(dataArg, 'target-profiles:write');
          const manager = this.opsServerRef.dcRouterRef.targetProfileManager;
          if (!manager) {
            return { success: false, message: 'Target profile manager not initialized' };
          }
          const id = await manager.createProfile({
            name: dataArg.name,
            description: dataArg.description,
            domains: dataArg.domains,
            targets: dataArg.targets,
            routeRefs: dataArg.routeRefs,
            allowRoutesByClientSourceIp: dataArg.allowRoutesByClientSourceIp,
            createdBy: userId,
          });
          await this.opsServerRef.dcRouterRef.routeConfigManager?.applyRoutes();
          await this.opsServerRef.dcRouterRef.vpnManager?.refreshAllClientSecurity();
          return { success: true, id };
        },
      ),
    );

    // Update a target profile
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateTargetProfile>(
        'updateTargetProfile',
        async (dataArg) => {
          await this.requireAuth(dataArg, 'target-profiles:write');
          const manager = this.opsServerRef.dcRouterRef.targetProfileManager;
          if (!manager) {
            return { success: false, message: 'Not initialized' };
          }
          await manager.updateProfile(dataArg.id, {
            name: dataArg.name,
            description: dataArg.description,
            domains: dataArg.domains,
            targets: dataArg.targets,
            routeRefs: dataArg.routeRefs,
            allowRoutesByClientSourceIp: dataArg.allowRoutesByClientSourceIp,
          });
          // Re-apply routes and refresh VPN client security to update access
          await this.opsServerRef.dcRouterRef.routeConfigManager?.applyRoutes();
          await this.opsServerRef.dcRouterRef.vpnManager?.refreshAllClientSecurity();
          return { success: true };
        },
      ),
    );

    // Delete a target profile
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteTargetProfile>(
        'deleteTargetProfile',
        async (dataArg) => {
          await this.requireAuth(dataArg, 'target-profiles:write');
          const manager = this.opsServerRef.dcRouterRef.targetProfileManager;
          if (!manager) {
            return { success: false, message: 'Not initialized' };
          }
          const result = await manager.deleteProfile(dataArg.id, dataArg.force);
          if (result.success) {
            // Re-apply routes and refresh VPN client security to update access
            await this.opsServerRef.dcRouterRef.routeConfigManager?.applyRoutes();
            await this.opsServerRef.dcRouterRef.vpnManager?.refreshAllClientSecurity();
          }
          return result;
        },
      ),
    );

    // Get VPN clients using a target profile
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetTargetProfileUsage>(
        'getTargetProfileUsage',
        async (dataArg) => {
          await this.requireAuth(dataArg, 'target-profiles:read');
          const manager = this.opsServerRef.dcRouterRef.targetProfileManager;
          if (!manager) {
            return { clients: [] };
          }
          return { clients: await manager.getProfileUsage(dataArg.id) };
        },
      ),
    );
  }
}
