import jwt from 'jsonwebtoken';
import environment from '../config/environment';
import logger from '../utils/logger';
import { JwtPayload, RefreshTokenPayload } from '../types/auth.types';

class TokenService {
  /**
   * Generate JWT access token
   */
  generateToken(payload: JwtPayload): string {
    try {
      const token = jwt.sign(
        {
          userId: payload.userId,
          email: payload.email,
          authentikSub: payload.authentikSub,
          groups: payload.groups ?? [],
          role: payload.role,
          type: 'access',
        },
        environment.jwt.secret,
        {
          expiresIn: environment.jwt.expiresIn as any,
        }
      );

      logger.info('Generated JWT token', { userId: payload.userId });
      return token;
    } catch (error) {
      logger.error('Failed to generate JWT token', { error });
      throw new Error('Token generation failed');
    }
  }

  /**
   * Verify and decode JWT token
   */
  verifyToken(token: string): JwtPayload {
    try {
      const decoded = jwt.verify(
        token,
        environment.jwt.secret
      ) as JwtPayload & { type?: string };

      if (decoded.type && decoded.type !== 'access') {
        throw new Error('Invalid token type');
      }

      logger.debug('JWT token verified', { userId: decoded.userId });
      return decoded;
    } catch (error) {
      if (error instanceof jwt.TokenExpiredError) {
        logger.warn('JWT token expired');
        throw new Error('Token expired');
      } else if (error instanceof jwt.JsonWebTokenError) {
        logger.warn('Invalid JWT token', { error: error.message });
        throw new Error('Invalid token');
      } else {
        logger.error('Failed to verify JWT token', { error });
        throw new Error('Token verification failed');
      }
    }
  }

  /**
   * Generate refresh token (longer lived)
   */
  generateRefreshToken(payload: RefreshTokenPayload): string {
    try {
      const token = jwt.sign(
        {
          userId: payload.userId,
          email: payload.email,
          type: 'refresh',
        },
        environment.jwt.secret,
        {
          expiresIn: '7d', // Refresh tokens valid for 7 days
        }
      );

      logger.info('Generated refresh token', { userId: payload.userId });
      return token;
    } catch (error) {
      logger.error('Failed to generate refresh token', { error });
      throw new Error('Refresh token generation failed');
    }
  }

  /**
   * Verify refresh token
   */
  verifyRefreshToken(token: string): RefreshTokenPayload {
    try {
      const decoded = jwt.verify(
        token,
        environment.jwt.secret
      ) as RefreshTokenPayload & { type?: string };

      if (decoded.type && decoded.type !== 'refresh') {
        throw new Error('Invalid token type');
      }

      logger.debug('Refresh token verified', { userId: decoded.userId });
      return decoded;
    } catch (error) {
      if (error instanceof jwt.TokenExpiredError) {
        logger.warn('Refresh token expired');
        throw new Error('Refresh token expired');
      } else if (error instanceof jwt.JsonWebTokenError) {
        logger.warn('Invalid refresh token', { error: error.message });
        throw new Error('Invalid refresh token');
      } else {
        logger.error('Failed to verify refresh token', { error });
        throw new Error('Refresh token verification failed');
      }
    }
  }

  /**
   * Decode token without verification (for debugging)
   */
  decodeToken(token: string): JwtPayload | null {
    try {
      const decoded = jwt.decode(token) as JwtPayload;
      return decoded;
    } catch (error) {
      logger.error('Failed to decode token', { error });
      return null;
    }
  }
}

export default new TokenService();
