import {
  BadRequestException,
  Injectable,
  Logger,
  ServiceUnavailableException,
  UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { generateToken, generateRefreshToken } from '@tria-plc/api-common/utils/token';
import axios, { AxiosInstance } from 'axios';
import { PrismaService } from '../../common/prisma.service';
import { FaydaConfig, FaydaPlatform } from '../../config/fayda.config';
import {
  generateCodeChallenge,
  generateCodeVerifier,
  generateState,
} from './utils/pkce.util';
import { generateClientAssertion } from './utils/client-assertion.util';
import { rebaseUrlOrigin } from '../../common/utils/redirect-origin.util';
import { VerifaydaCallbackDto, VerificationStatusDto } from './verifayda.dto';
import {
  FaydaTokenExchangeException,
  FaydaUserInfoException,
} from './verifayda.errors';
import {
  FaydaTokenResponse,
  FaydaUserInfo,
  NormalizedFaydaUserInfo,
  VerifaydaPurpose,
} from './verifayda.types';

export interface VerifaydaPassengerData {
  fullName: string;
  dateOfBirth: Date;
  gender?: string;
  nationality?: string;
  profileData?: Record<string, any>;
}

export interface VerifaydaVerificationResult {
  verified: boolean;
  passengerData?: VerifaydaPassengerData;
  failureReason?: string;
}

export interface StartVerificationInput {
  purpose: VerifaydaPurpose;
  platform?: FaydaPlatform;
  userId?: string;   // iamUserId of the authenticated user, if any
  wantsPasswordSetup?: boolean;
  /**
   * Allowlisted browser origin the request came from (e.g. https://bookingedr.et
   * or https://passenger.edrsc.com), already validated by the controller. For
   * WEB sessions the eSignet redirect_uri host is swapped to this so the user
   * lands back on the same domain. Null/undefined keeps the configured default.
   */
  requestOrigin?: string | null;
}

export interface FaydaUserSummary {
  id: string;
  email: string;
  role: string;
  passengerId?: string;
  agentId?: string;
}

/**
 * Result of completing a verification. `verified` is always true on success.
 * LOGIN additionally returns a JWT + user; VERIFY returns the verified identity
 * attributes (name, email, phone, dob, gender) for the caller to consume.
 */
export interface CompleteVerificationResult {
  purpose: VerifaydaPurpose;
  verified: boolean;
  token?: string;
  refreshToken?: string;
  requiresPassword?: boolean;
  promptPasswordSetup?: boolean;
  iamUserId?: string;
  user?: FaydaUserSummary;
  fullName?: string;
  email?: string;
  phoneNumber?: string;
  birthdate?: string;
  gender?: string;
  userDataSaved?: boolean;
}

@Injectable()
export class VerifaydaService {
  private readonly logger = new Logger(VerifaydaService.name);


  private readonly faydaConfig: FaydaConfig;

  private readonly httpClient: AxiosInstance;
  private readonly stubEnabled: boolean;
  private readonly stubApiUrl: string;
  private readonly stubApiKey: string;

  constructor(
    private readonly config: ConfigService,
    private readonly prisma: PrismaService,
    @InjectDataSource() private readonly dataSource: DataSource,
  ) {
    const fayda = this.config.get<FaydaConfig>('fayda');
    if (!fayda) {
      throw new Error('Fayda config namespace not registered');
    }
    this.faydaConfig = fayda;

    this.stubEnabled = this.config.get<boolean>('VERIFAYDA_ENABLED', false);
    this.stubApiUrl = this.config.get<string>(
      'VERIFAYDA_API_URL',
      'https://api.verifayda.gov.et/v2',
    );
    this.stubApiKey = this.config.get<string>('VERIFAYDA_API_KEY', '');
    
    this.logger.log(`Verifayda configuration: enabled=${this.stubEnabled}, url=${this.stubApiUrl}`);
    
    // Only create HTTP client if Verifayda is enabled
    if (this.stubEnabled) {
      this.httpClient = axios.create({
        baseURL: this.stubApiUrl,
        timeout: 10000,
        headers: { 'Content-Type': 'application/json', 'X-API-Key': this.stubApiKey },
      });
      this.logger.log('Verifayda HTTP client created');
    } else {
      this.logger.log('Verifayda HTTP client NOT created (disabled)');
    }
  }

  // ==========================================================================
  // OIDC flow
  // ==========================================================================

  async startVerification(input: StartVerificationInput): Promise<string> {
    if (!this.faydaConfig.enabled) {
      throw new ServiceUnavailableException({
        code: 'FAYDA_DISABLED',
        message: 'Fayda integration is not enabled',
      });
    }

    const state = generateState();
    const codeVerifier = generateCodeVerifier();
    const codeChallenge = generateCodeChallenge(codeVerifier);
    const expiresAt = new Date(
      Date.now() + this.faydaConfig.sessionTtlMinutes * 60_000,
    );

    const platform = input.platform ?? 'WEB';
    // WEB sessions follow the domain the user came in on (bookingedr.et vs
    // passenger.edrsc.com); MOBILE always uses the native base redirect_uri.
    // Persist the exact URI so token exchange at /complete reuses it verbatim —
    // eSignet requires the redirect_uri to match between authorize and token.
    const redirectUri =
      platform === 'MOBILE'
        ? this.redirectUriForPlatform('MOBILE')
        : rebaseUrlOrigin(
            this.faydaConfig.webRedirectUri,
            input.requestOrigin ?? null,
          ) ?? this.faydaConfig.webRedirectUri;

    await this.prisma.faydaVerificationSession.create({
      data: {
        state,
        codeVerifier,
        purpose: input.purpose,
        platform,
        redirectUri,
        saveToAccount: input.wantsPasswordSetup ?? false,
        iamUserId: input.userId ?? null,
        expiresAt,
      },
    });

    this.logger.log(
      `Fayda verification started: purpose=${input.purpose} platform=${platform} userId=${input.userId ?? 'none'} redirectUri=${redirectUri}`,
    );

    return this.buildAuthorizationUrl({
      state,
      codeChallenge,
      redirectUri,
    });
  }

  /** WEB clients use `webRedirectUri`; MOBILE uses the base `redirectUri`. */
  private redirectUriForPlatform(platform?: FaydaPlatform): string {
    return platform === 'MOBILE'
      ? this.faydaConfig.redirectUri
      : this.faydaConfig.webRedirectUri;
  }


  async completeVerification(
    query: VerifaydaCallbackDto,
  ): Promise<CompleteVerificationResult> {
    if (query.error) {
      this.logger.warn(`Fayda callback returned error: ${query.error}`);
      if (query.state) {
        await this.markSessionFailed(
          query.state,
          query.error,
          query.error_description,
        );
      }
      throw new BadRequestException({
        code: 'FAYDA_AUTH_ERROR',
        message: query.error,
        description: query.error_description,
      });
    }

    if (!query.code || !query.state) {
      throw new BadRequestException({
        code: 'FAYDA_MISSING_PARAMETERS',
        message: 'code and state are required',
      });
    }

    const session = await this.prisma.faydaVerificationSession.findUnique({
      where: { state: query.state },
    });
    if (!session || session.status !== 'PENDING') {
      this.logger.warn('Fayda complete with unknown or non-pending state');
      throw new BadRequestException({
        code: 'FAYDA_INVALID_STATE',
        message: 'Verification session is invalid or already used',
      });
    }
    if (session.expiresAt.getTime() < Date.now()) {
      await this.markSessionFailed(query.state, 'session_expired');
      throw new BadRequestException({
        code: 'FAYDA_SESSION_EXPIRED',
        message: 'Verification session has expired; start again',
      });
    }

    try {
      const tokens = await this.exchangeCodeForTokens(
        query.code,
        session.codeVerifier,
        // Reuse the exact redirect_uri sent at authorize (persisted on the
        // session). Fall back to the platform default for sessions created
        // before this column existed.
        session.redirectUri ??
          this.redirectUriForPlatform(session.platform as FaydaPlatform),
      );
      const userInfo = await this.fetchUserInfo(tokens.access_token);
      const normalized = this.normalizeUserInfo(userInfo);

      if (!normalized.sub) {
        throw new FaydaUserInfoException('Fayda userinfo missing required sub');
      }

      let result: CompleteVerificationResult;
      if (session.purpose === 'LOGIN') {
        const { userId } = await this.handleLoginSuccess(normalized);
        const login = await this.issueLoginToken(userId);
        result = { purpose: 'LOGIN', verified: true, ...login };
      } else {
        // VERIFY — prove identity, save to IAM, return verified attributes + short-lived token.
        const { iamUserId, userDataSaved } = await this.upsertIamUser(normalized);

        let sessionToken: { token: string; refreshToken: string; requiresPassword: boolean } | undefined;
        if (iamUserId) {
          try {
            sessionToken = await this.createFaydaSession(iamUserId);
          } catch (err) {
            this.logger.warn(`Fayda session creation failed: ${(err as Error).message}`);
          }
        }

        result = {
          purpose: 'VERIFY',
          verified: true,
          fullName: normalized.fullName,
          email: normalized.email,
          phoneNumber: normalized.phoneNumber,
          birthdate: normalized.birthdate,
          gender: normalized.gender,
          userDataSaved,
          iamUserId: iamUserId ?? undefined,
          token: sessionToken?.token,
          refreshToken: sessionToken?.refreshToken,
          requiresPassword: sessionToken?.requiresPassword,
          promptPasswordSetup: session.saveToAccount && (sessionToken?.requiresPassword ?? false),
        };
      }

      await this.prisma.faydaVerificationSession.update({
        where: { id: session.id },
        data: { status: 'COMPLETED', completedAt: new Date(), codeVerifier: '' },
      });

      this.logger.log(
        `Fayda verification completed: purpose=${session.purpose} platform=${session.platform}`,
      );
      return result;
    } catch (err) {
      const reason = this.classifyFailureReason(err);
      this.logger.error(
        `Fayda verification failed: reason=${reason} message=${(err as Error).message}`,
      );
      await this.markSessionFailed(
        query.state,
        reason,
        (err as Error).message,
      );
      throw err;
    }
  }

  private async issueLoginToken(
    _userId: string,
  ): Promise<{ token: string; user: FaydaUserSummary }> {
    throw new UnauthorizedException({
      code: 'FAYDA_LOGIN_MIGRATED_TO_IAM',
      message: 'Fayda login tokens are issued by the IAM package auth endpoints.',
    });
  }

  async getVerificationStatus(iamUserId: string): Promise<VerificationStatusDto> {
    const rows = await this.dataSource.query<{ verified_by: string | null; updated_at: Date | null; name: { en: string; am: string } | null }[]>(
      `SELECT verified_by, updated_at, name FROM iam.users WHERE id = $1 LIMIT 1`,
      [iamUserId],
    );
    const iam = rows[0] ?? null;
    const faydaVerified = iam?.verified_by === 'fayda';
    const faydaVerifiedAt = faydaVerified && iam?.updated_at ? new Date(iam.updated_at) : undefined;
    const fullName = iam?.name?.en ?? iam?.name?.am ?? undefined;
    return { verified: faydaVerified, verifiedAt: faydaVerifiedAt, fullName };
  }

  // ==========================================================================
  // OIDC internals
  // ==========================================================================

  private buildAuthorizationUrl(args: {
    state: string;
    codeChallenge: string;
    redirectUri: string;
  }): string {
    const params = new URLSearchParams({
      client_id: this.faydaConfig.clientId,
      response_type: 'code',
      redirect_uri: args.redirectUri,
      scope: this.faydaConfig.scope,
      state: args.state,
      code_challenge: args.codeChallenge,
      code_challenge_method: 'S256',
      acr_values: this.faydaConfig.acrValues,
      claims_locales: this.faydaConfig.claimsLocales,
    });

    // Every claim is marked essential so eSignet shows them locked/pre-checked
    // on the consent screen — the user cannot toggle any off; they either
    // consent to all of them or the whole flow is cancelled (?error=...).
    const claims = {
      userinfo: {
        name: { essential: true },
        phone_number: { essential: true },
        email: { essential: true },
        birthdate: { essential: true },
        gender: { essential: true },
        address: { essential: true },
        nationality: { essential: true },
        picture: { essential: true },
      },
      id_token: {},
    };
    params.set('claims', JSON.stringify(claims));

    return `${this.faydaConfig.authorizationEndpoint}?${params.toString()}`;
  }

  private async exchangeCodeForTokens(
    code: string,
    codeVerifier: string,
    redirectUri: string,
  ): Promise<FaydaTokenResponse> {
    const clientAssertion = await generateClientAssertion({
      clientId: this.faydaConfig.clientId,
      audience: this.faydaConfig.tokenEndpoint,
      privateJwk: this.faydaConfig.privateJwk,
    });

    const body = new URLSearchParams({
      grant_type: 'authorization_code',
      code,
      redirect_uri: redirectUri,
      client_id: this.faydaConfig.clientId,
      client_assertion_type:
        'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
      client_assertion: clientAssertion,
      code_verifier: codeVerifier,
    });

    const response = await fetch(this.faydaConfig.tokenEndpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body,
    });

    if (!response.ok) {
      let detail = '';
      try {
        detail = await response.text();
      } catch {
        // ignore
      }
      throw new FaydaTokenExchangeException(
        `Fayda token endpoint returned ${response.status}${detail ? `: ${detail}` : ''}`,
      );
    }

    return (await response.json()) as FaydaTokenResponse;
  }

  private async fetchUserInfo(accessToken: string): Promise<FaydaUserInfo> {
    const response = await fetch(this.faydaConfig.userInfoEndpoint, {
      method: 'GET',
      headers: { Authorization: `Bearer ${accessToken}` },
    });

    if (!response.ok) {
      throw new FaydaUserInfoException(
        `Fayda userinfo endpoint returned ${response.status}`,
      );
    }

    const contentType = response.headers.get('content-type') ?? '';
    const raw = await response.text();

    if (contentType.includes('application/json')) {
      return JSON.parse(raw) as FaydaUserInfo;
    }

    // Signed JWT response — decode payload (signature verification = production TODO)
    if (raw.split('.').length === 3) {
      const payloadB64 = raw.split('.')[1];
      const normalizedB64 = payloadB64.replace(/-/g, '+').replace(/_/g, '/');
      const json = Buffer.from(normalizedB64, 'base64').toString('utf8');
      return JSON.parse(json) as FaydaUserInfo;
    }

    throw new FaydaUserInfoException(
      'Unsupported Fayda userinfo response format',
    );
  }

  private normalizeUserInfo(raw: FaydaUserInfo): NormalizedFaydaUserInfo {
    const nameEn   = raw['name#en'] as string | undefined;
    const nameAm   = raw['name#am'] as string | undefined;
    const genderEn = raw['gender#en'] as string | undefined;
    const genderAm = raw['gender#am'] as string | undefined;
    const addressEn = raw['address#en'] as string | undefined;
    const addressAm = raw['address#am'] as string | undefined;
    const rawPhone  = (raw.phone_number ?? raw['phone_number#en'] ?? raw['phone_number#am'] ?? raw.phone) as string | undefined;

    return {
      sub: raw.sub,
      fullName: (raw.name as string | undefined) ?? nameEn ?? nameAm,
      phoneNumber: rawPhone ? this.standardizePhoneNumber(rawPhone) : undefined,
      rawPhoneNumber: rawPhone,
      email: raw.email as string | undefined,
      gender: genderEn ?? genderAm ?? (raw.gender as string | undefined),
      birthdate: raw.birthdate as string | undefined,
      picture: raw.picture as string | undefined,
      nameEn,
      nameAm,
      genderEn,
      genderAm,
      addressEn,
      addressAm,
    };
  }

  private standardizePhoneNumber(phone: string): string {
    const digits = phone.replace(/\D/g, '');
    if (digits.startsWith('251')) return `+${digits}`;
    if (digits.startsWith('0'))   return `+251${digits.slice(1)}`;
    return `+${digits}`;
  }

  // LOGIN via Fayda is now handled entirely by the IAM package's own OIDC flow.
  // This method is kept as a stub so completeVerification() still compiles;
  // it throws immediately without touching the database.
  private async handleLoginSuccess(
    _normalized: NormalizedFaydaUserInfo,
  ): Promise<{ userId: string }> {
    throw new UnauthorizedException({
      code: 'FAYDA_LOGIN_MIGRATED_TO_IAM',
      message: 'Fayda login tokens are issued by the IAM package at /v1/auth/fayda endpoints.',
    });
  }

  private async upsertIamUser(
    normalized: NormalizedFaydaUserInfo,
  ): Promise<{ iamUserId: string | null; userDataSaved: boolean }> {
    try {
      const iamMetadata = {
        sub: normalized.sub,
        address: { am: normalized.addressAm ?? '', en: normalized.addressEn ?? '' },
        email: normalized.email ?? '',
        gender: { am: normalized.genderAm ?? '', en: normalized.genderEn ?? '' },
        name:   { am: normalized.nameAm   ?? '', en: normalized.nameEn   ?? '' },
        phoneNumber: normalized.rawPhoneNumber ?? '',
        // Persist the identity fields the passenger booking form needs. Fayda returns
        // these on every verification but they were previously dropped, leaving the
        // logged-in/verified form with nothing to prefill. birthdate arrives as
        // YYYY/MM/DD — store it as the ISO YYYY-MM-DD the form expects. A Fayda-verified
        // holder is an Ethiopian national ID holder, so nationality is always Ethiopian.
        dateOfBirth: normalized.birthdate ? normalized.birthdate.replace(/\//g, '-') : '',
        nationality: 'ETHIOPIAN',
      };

      // Step 1 — already linked to this Fayda sub; refresh metadata (backfills the newly
      // persisted dateOfBirth/nationality for users linked before this change) and ensure
      // verified_by is set.
      const bySub = await this.dataSource.query<{ id: string }[]>(
        `SELECT id FROM iam.users WHERE metadata->>'sub' = $1 LIMIT 1`,
        [normalized.sub],
      );
      if (bySub.length > 0) {
        await this.dataSource.query(
          `UPDATE iam.users
              SET metadata    = COALESCE(metadata, '{}'::jsonb) || $1::jsonb,
                  verified_by = 'fayda',
                  updated_at  = NOW()
            WHERE id = $2`,
          [JSON.stringify(iamMetadata), bySub[0].id],
        );
        return { iamUserId: bySub[0].id, userDataSaved: true };
      }

      // Step 2 — existing user by phone or email, not yet Fayda-verified
      const conditions: string[] = [];
      const params: unknown[] = [];
      if (normalized.phoneNumber) {
        params.push(normalized.phoneNumber);
        conditions.push(`phone_number = $${params.length}`);
      }
      if (normalized.email) {
        params.push(normalized.email);
        conditions.push(`email = $${params.length}`);
      }
      if (conditions.length > 0) {
        const byContact = await this.dataSource.query<{ id: string }[]>(
          `SELECT id FROM iam.users WHERE ${conditions.join(' OR ')} LIMIT 1`,
          params,
        );
        if (byContact.length > 0) {
          const existingId = byContact[0].id;
          await this.dataSource.query(
            `UPDATE iam.users
                SET metadata    = COALESCE(metadata, '{}'::jsonb) || $1::jsonb,
                    verified_by = 'fayda',
                    updated_at  = NOW()
              WHERE id = $2`,
            [JSON.stringify(iamMetadata), existingId],
          );
          return { iamUserId: existingId, userDataSaved: true };
        }
      }

      // Step 3 — new user
      const name     = { am: normalized.nameAm ?? '', en: normalized.nameEn ?? '' };
      const username = normalized.phoneNumber ?? normalized.email ?? normalized.sub;
      const inserted = await this.dataSource.query<{ id: string }[]>(
        `INSERT INTO iam.users (
            id, name, username, email, phone_number, metadata,
            user_type, status, is_active, has_set_password,
            is_phone_number_verified, verified_by,
            created_at, updated_at
          ) VALUES (
            gen_random_uuid(), $1::jsonb, $2, $3, $4, $5::jsonb,
            'individual', 'submitted', true, false,
            false, 'fayda',
            NOW(), NOW()
          ) RETURNING id`,
        [
          JSON.stringify(name),
          username,
          normalized.email   ?? null,
          normalized.phoneNumber ?? null,
          JSON.stringify(iamMetadata),
        ],
      );
      return { iamUserId: inserted[0].id, userDataSaved: true };
    } catch (err) {
      this.logger.error(`Fayda IAM upsert failed: ${(err as Error).message}`);
      return { iamUserId: null, userDataSaved: false };
    }
  }

  private async createFaydaSession(
    iamUserId: string,
  ): Promise<{ token: string; refreshToken: string; requiresPassword: boolean }> {
    const rows = await this.dataSource.query<{
      id: string;
      email: string;
      name: { en: string; am: string } | null;
      username: string;
      phone_number: string | null;
      has_set_password: boolean;
      status: string;
    }[]>(
      `SELECT id, email, name, username, phone_number, has_set_password, status
         FROM iam.users WHERE id = $1 LIMIT 1`,
      [iamUserId],
    );
    if (!rows.length) throw new Error(`IAM user ${iamUserId} not found`);
    const u = rows[0];

    const userInfo = {
      id: u.id,
      email: u.email ?? '',
      name: u.name ?? { en: '', am: '' },
      userType: 'individual',
      status: u.status,
      hasSetPassword: u.has_set_password,
      isPhoneNumberVerified: false,
      hasFinishedRegistration: false,
      hasFinishedDMSOnboarding: false,
      username: u.username,
      phoneNumber: u.phone_number ?? '',
      roles: [],
      permissions: [],
      employee: [],
    };

    const sessions = await this.dataSource.query<{ id: string }[]>(
      `INSERT INTO iam.sessions
          (id, email, device, "userInfo", expiry_time, refresh_count, status, user_id)
        VALUES (gen_random_uuid(), $1, 'fayda-verify', $2::jsonb, NOW() + INTERVAL '1 day', 0, 'ACTIVE', $3)
        ON CONFLICT (user_id, device) DO UPDATE
          SET status = 'ACTIVE', "userInfo" = EXCLUDED."userInfo",
              expiry_time = NOW() + INTERVAL '1 day', updated_at = NOW()
        RETURNING id`,
      [u.email ?? '', JSON.stringify(userInfo), iamUserId],
    );

    const sessionId = sessions[0].id;
    const token = generateToken({ id: sessionId });
    const refreshToken = generateRefreshToken({ id: sessionId });

    return { token, refreshToken, requiresPassword: !u.has_set_password };
  }

  private async markSessionFailed(
    state: string,
    errorCode: string,
    errorDescription?: string,
  ): Promise<void> {
    await this.prisma.faydaVerificationSession.updateMany({
      where: { state, status: 'PENDING' },
      data: {
        status: 'FAILED',
        errorCode,
        errorDescription: errorDescription ?? null,
        completedAt: new Date(),
        codeVerifier: '',
      },
    });
  }

  private classifyFailureReason(err: unknown): string {
    if (err instanceof FaydaTokenExchangeException) return 'token_exchange_failed';
    if (err instanceof FaydaUserInfoException) return 'userinfo_failed';
    return 'verification_failed';
  }

  // ==========================================================================
  // DEPRECATED: legacy stub flow
  // ==========================================================================

  /** @deprecated Use the OIDC flow instead. Retained until cleanup. */
  async verifyNationalId(
    nationalId: string,
    bookingId?: string,
  ): Promise<VerifaydaVerificationResult> {
    this.logger.log(`verifyNationalId called: stubEnabled=${this.stubEnabled}, type=${typeof this.stubEnabled}`);
    
    if (!this.stubEnabled) {
      this.logger.warn('Verifayda not configured — returning mock data (development mode)');
      return {
        verified: true,
        passengerData: {
          fullName: 'Mock Passenger',
          dateOfBirth: new Date('1990-01-01'),
          gender: 'Male',
          nationality: 'Ethiopian',
        },
      };
    }

    const requestPayload = {
      nationalId,
      requestedFields: ['fullName', 'dateOfBirth', 'gender', 'nationality'],
      timestamp: new Date().toISOString(),
    };

    try {
      this.logger.log('Verifying national ID via legacy Verifayda stub');
      const response = await this.httpClient.post('/verify', requestPayload);
      const { data } = response;

      if (data.status === 'verified' && data.citizen) {
        const passengerData: VerifaydaPassengerData = {
          fullName: data.citizen.fullName,
          dateOfBirth: new Date(data.citizen.dateOfBirth),
          gender: data.citizen.gender,
          nationality: data.citizen.nationality || 'Ethiopian',
          profileData: data.citizen,
        };

        await this.prisma.verifaydaVerification.create({
          data: {
            bookingId,
            nationalId,
            requestPayload,
            responsePayload: data,
            verified: true,
            verifiedAt: new Date(),
          },
        });

        return { verified: true, passengerData };
      }

      const failureReason = data.message || 'Verification failed';
      await this.prisma.verifaydaVerification.create({
        data: {
          bookingId,
          nationalId,
          requestPayload,
          responsePayload: data,
          verified: false,
          failureReason,
        },
      });
      return { verified: false, failureReason };
    } catch (error: any) {
      const errorMessage =
        error.response?.data?.message || error.message || 'Unknown error';
      await this.prisma.verifaydaVerification.create({
        data: {
          bookingId,
          nationalId,
          requestPayload,
          verified: false,
          failureReason: errorMessage,
        },
      });
      this.logger.error(`Verifayda stub error: ${errorMessage}`);
      throw new BadRequestException(
        `National ID verification failed: ${errorMessage}`,
      );
    }
  }

  /** @deprecated Use `faydaConfig.enabled` for the OIDC flow. */
  isEnabled(): boolean {
    return this.stubEnabled;
  }
}
