/home/bdqbpbxa/dev-subdomains/admin.pixory.goodface.com.ua/src/policies/auth0-optional.ts
import utils from"@strapi/utils";
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
import { Context } from 'koa';
import { env } from 'src/config/env';

const { PolicyError } = utils.errors;

const client = jwksClient({
  jwksUri: `${env.auth0.issuerBaseUrl}.well-known/jwks.json`,
});

function verifyTokenAsync(token: string, audience: string, issuer: string): Promise<any> {
  return new Promise((resolve, reject) => {
    jwt.verify(
      token,
      (header, callback) => {
        if (!header.kid) {
          return callback(new Error('Missing kid in token header'));
        }
        client.getSigningKey(header.kid, function (err, key) {
          if (err) return callback(err);
          const signingKey = key.getPublicKey();
          callback(null, signingKey);
        });
      },
      {
        audience,
        issuer,
        algorithms: ['RS256'],
      },
      (err, decoded) => {
        if (err) return reject(err);
        resolve(decoded);
      }
    );
  });
}

const auth0OptionalPolicy = async (ctx: Context, config, { strapi }) => {
  try {
    const authHeader = ctx.request.headers.authorization;

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return true;
    }

    const token = authHeader.split(' ')[1];

    const decoded = await verifyTokenAsync(
      token,
      env.auth0.audience,
      env.auth0.issuerBaseUrl
    );
    
    const user = await strapi.db.query('plugin::users-permissions.user').findOne({
      where: { sub: decoded.sub }
    });

    ctx.state.user = {
      id: user?.id || null,
      sub: decoded.sub,
      ...decoded,
    };

    return true;
  } catch (error) {
    if (error instanceof PolicyError) {
      throw error;
    }
    
    if (error.name === 'JsonWebTokenError') {
      throw new PolicyError('Invalid token format', { status: 401 });
    }
    
    if (error.name === 'TokenExpiredError') {
      throw new PolicyError('Token has expired', { status: 401 });
    }
    
    if (error.name === 'NotBeforeError') {
      throw new PolicyError('Token not active yet', { status: 401 });
    }

    // Handle JWKS errors
    if (error.message && error.message.includes('kid')) {
      throw new PolicyError('Invalid token key identifier', { status: 401 });
    }

    // Generic error fallback
    strapi.log.error('Auth0 policy error:', error);
    throw new PolicyError('Authentication failed', { status: 401 });
  }
};

export default auth0OptionalPolicy;