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

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

export class AdminHandler {
  public typedrouter = new plugins.typedrequest.TypedRouter();
  public smartjwtInstance!: plugins.smartjwt.SmartJwt<IJwtData>;

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

  public async initialize(): Promise<void> {
    this.smartjwtInstance = new plugins.smartjwt.SmartJwt();
    await this.smartjwtInstance.init();
    await this.smartjwtInstance.createNewKeyPair();
    this.registerHandlers();
  }

  private registerHandlers(): void {
    // Login
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_AdminLogin>(
        'adminLogin',
        async (dataArg) => {
          const expectedUsername = Deno.env.get('GITOPS_ADMIN_USERNAME') || 'admin';
          const expectedPassword = Deno.env.get('GITOPS_ADMIN_PASSWORD') || 'admin';

          if (dataArg.username !== expectedUsername || dataArg.password !== expectedPassword) {
            throw new plugins.typedrequest.TypedResponseError('Invalid credentials');
          }

          const expiresAt = Date.now() + 24 * 3600 * 1000;
          const userId = 'admin';
          const jwt = await this.smartjwtInstance.createJWT({
            userId,
            status: 'loggedIn',
            expiresAt,
          });

          logger.info(`User logged in: ${dataArg.username}`);

          return {
            identity: {
              jwt,
              userId,
              username: dataArg.username,
              expiresAt,
              role: 'admin' as const,
            },
          };
        },
      ),
    );

    // Logout
    this.typedrouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_AdminLogout>(
        'adminLogout',
        async (_dataArg) => {
          return { ok: true };
        },
      ),
    );

    // Verify Identity
    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);
            if (jwtData.expiresAt < Date.now()) return { valid: false };
            if (jwtData.status !== 'loggedIn') return { valid: false };
            return {
              valid: true,
              identity: {
                jwt: dataArg.identity.jwt,
                userId: jwtData.userId,
                username: dataArg.identity.username,
                expiresAt: jwtData.expiresAt,
                role: dataArg.identity.role,
              },
            };
          } catch {
            return { valid: false };
          }
        },
      ),
    );
  }

  // Guard for valid identity
  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);
        if (jwtData.expiresAt < Date.now()) return false;
        if (jwtData.status !== 'loggedIn') return false;
        if (dataArg.identity.expiresAt !== jwtData.expiresAt) return false;
        if (dataArg.identity.userId !== jwtData.userId) return false;
        return true;
      } catch {
        return false;
      }
    },
    { failedHint: 'identity is not valid', name: 'validIdentityGuard' },
  );
}
