import { Env, JWTPayload, User } from '../types';
import { verifyJWT, createJWT, createRefreshToken } from '../utils/jwt';
import { StorageService } from './storage';

export class AuthService {
  private storage: StorageService;

  constructor(private env: Env) {
    this.storage = new StorageService(env.DB);
  }

  // Verify password hash (compare with stored hash)
  async verifyPassword(inputHash: string, storedHash: string): Promise<boolean> {
    const input = new TextEncoder().encode(inputHash);
    const stored = new TextEncoder().encode(storedHash);
    if (input.length !== stored.length) return false;

    let diff = 0;
    for (let i = 0; i < input.length; i++) {
      diff |= input[i] ^ stored[i];
    }
    return diff === 0;
  }

  // Generate access token
  async generateAccessToken(user: User): Promise<string> {
    return createJWT(
      {
        sub: user.id,
        email: user.email,
        name: user.name,
        sstamp: user.securityStamp,
      },
      this.env.JWT_SECRET
    );
  }

  // Generate refresh token
  async generateRefreshToken(userId: string): Promise<string> {
    const token = createRefreshToken();
    await this.storage.saveRefreshToken(token, userId);
    return token;
  }

  // Verify access token from Authorization header
  async verifyAccessToken(authHeader: string | null): Promise<JWTPayload | null> {
    if (!authHeader) return null;

    const parts = authHeader.split(' ');
    if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {
      return null;
    }

    const payload = await verifyJWT(parts[1], this.env.JWT_SECRET);
    if (!payload) return null;

    // Verify security stamp - ensures token is invalidated after password change
    const user = await this.storage.getUserById(payload.sub);
    if (!user) return null;
    
    if (payload.sstamp !== user.securityStamp) {
      return null; // Token was issued before password change
    }

    return payload;
  }

  // Refresh access token
  async refreshAccessToken(refreshToken: string): Promise<{ accessToken: string; user: User } | null> {
    const userId = await this.storage.getRefreshTokenUserId(refreshToken);
    if (!userId) return null;

    const user = await this.storage.getUserById(userId);
    if (!user) return null;
    if (user.status !== 'active') {
      await this.storage.deleteRefreshToken(refreshToken);
      return null;
    }

    const accessToken = await this.generateAccessToken(user);
    return { accessToken, user };
  }
}
