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

export interface IJwtData {
  userId: string;
  status: 'loggedIn' | 'loggedOut';
  expiresAt: number;
}

export class AdminHandler {
  public typedrouter = new plugins.typedrequest.TypedRouter();
  
  // JWT instance
  public smartjwtInstance!: plugins.smartjwt.SmartJwt<IJwtData>;
  
  // Simple in-memory user storage (in production, use proper database)
  private users = new Map<string, {
    id: string;
    username: string;
    password: string;
    role: string;
  }>();
  
  constructor(private opsServerRef: OpsServer) {
    // Add this handler's router to the parent
    this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter);
  }
  
  public async initialize(): Promise<void> {
    await this.initializeJwt();
    this.initializeDefaultUsers();
    this.registerHandlers();
  }
  
  private async initializeJwt(): Promise<void> {
    this.smartjwtInstance = new plugins.smartjwt.SmartJwt();
    await this.smartjwtInstance.init();
    
    // For development, create new keypair each time
    // In production, load from storage like cloudly does
    await this.smartjwtInstance.createNewKeyPair();
  }
  
  private initializeDefaultUsers(): void {
    // Add default admin user
    const adminId = plugins.uuid.v4();
    this.users.set(adminId, {
      id: adminId,
      username: 'admin',
      password: 'admin',
      role: 'admin',
    });
  }
  
  private registerHandlers(): void {
    // Admin Login Handler
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_AdminLoginWithUsernameAndPassword>(
        'adminLoginWithUsernameAndPassword',
        async (dataArg) => {
          try {
            // Find user by username and password
            let user: { id: string; username: string; password: string; role: string } | null = null;
            for (const [_, userData] of this.users) {
              if (userData.username === dataArg.username && userData.password === dataArg.password) {
                user = userData;
                break;
              }
            }
            
            if (!user) {
              throw new plugins.typedrequest.TypedResponseError('login failed');
            }
            
            const expiresAtTimestamp = Date.now() + 3600 * 1000 * 24; // 24 hours
            
            const jwt = await this.smartjwtInstance.createJWT({
              userId: user.id,
              status: 'loggedIn',
              expiresAt: expiresAtTimestamp,
            });
            
            return {
              identity: {
                jwt,
                userId: user.id,
                name: user.username,
                expiresAt: expiresAtTimestamp,
                role: user.role,
                type: 'user',
              },
            };
          } catch (error) {
            if (error instanceof plugins.typedrequest.TypedResponseError) {
              throw error;
            }
            throw new plugins.typedrequest.TypedResponseError('login failed');
          }
        }
      )
    );
    
    // Admin Logout Handler
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_AdminLogout>(
        'adminLogout',
        async (dataArg) => {
          // In a real implementation, you might want to blacklist the JWT
          // For now, just return success
          return {
            success: true,
          };
        }
      )
    );
    
    // Verify Identity Handler
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_VerifyIdentity>(
        'verifyIdentity',
        async (dataArg) => {
          if (!dataArg.identity?.jwt) {
            return {
              valid: false,
            };
          }
          
          try {
            const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
            
            // Check if expired
            if (jwtData.expiresAt < Date.now()) {
              return {
                valid: false,
              };
            }
            
            // Check if logged in
            if (jwtData.status !== 'loggedIn') {
              return {
                valid: false,
              };
            }
            
            // Find user
            const user = this.users.get(jwtData.userId);
            if (!user) {
              return {
                valid: false,
              };
            }
            
            return {
              valid: true,
              identity: {
                jwt: dataArg.identity.jwt,
                userId: user.id,
                name: user.username,
                expiresAt: jwtData.expiresAt,
                role: user.role,
                type: 'user',
              },
            };
          } catch (error) {
            return {
              valid: false,
            };
          }
        }
      )
    );
  }
  
  /**
   * Create a guard for valid identity (matching cloudly pattern)
   */
  public validIdentityGuard = new plugins.smartguard.Guard<{
    identity: interfaces.data.IIdentity;
  }>(
    async (dataArg) => {
      if (!dataArg.identity?.jwt) {
        return false;
      }
      
      try {
        const jwtData = await this.smartjwtInstance.verifyJWTAndGetData(dataArg.identity.jwt);
        
        // Check expiration
        if (jwtData.expiresAt < Date.now()) {
          return false;
        }
        
        // Check status
        if (jwtData.status !== 'loggedIn') {
          return false;
        }
        
        // Verify data hasn't been tampered with
        if (dataArg.identity.expiresAt !== jwtData.expiresAt) {
          return false;
        }
        
        if (dataArg.identity.userId !== jwtData.userId) {
          return false;
        }
        
        return true;
      } catch (error) {
        return false;
      }
    },
    {
      failedHint: 'identity is not valid',
      name: 'validIdentityGuard',
    }
  );
  
  /**
   * Create a guard for admin identity (matching cloudly pattern)
   */
  public adminIdentityGuard = new plugins.smartguard.Guard<{
    identity: interfaces.data.IIdentity;
  }>(
    async (dataArg) => {
      // First check if identity is valid
      const isValid = await this.validIdentityGuard.exec(dataArg);
      if (!isValid) {
        return false;
      }
      
      // Check if user has admin role
      return dataArg.identity.role === 'admin';
    },
    {
      failedHint: 'user is not admin',
      name: 'adminIdentityGuard',
    }
  );
}