import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from "@nestjs/common"
import { Observable } from "rxjs"
import { failureResponse } from "../common/response/response"
import { messageKey } from "../constants/message-keys"
import { AuthService } from "../modules/auth/v1/auth.service"
import moment from "moment"
import { getCurrentEnvironment, validationMessage } from "../utils/helpers"

// const permissionLevels: Record<string, string[]> = {
//   Admin: ["GET", "POST", "PUT", "DELETE", "PATCH"],
//   Editor: ["GET", "POST", "PUT", "PATCH"],
//   Viewer: ["GET"],
//   None: [],
// }

interface AuthenticatedRequest extends Request {
  user: any
}

@Injectable()
export class AuthGuardMiddleware implements CanActivate {
  constructor(private readonly authService: AuthService) {}

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest()
    return this.validateRequest(request)
  }

  async validateRequest(req: AuthenticatedRequest): Promise<boolean> {
    if (getCurrentEnvironment() === "local") {
      return true
    }
    // Extract the token from the request headers
    // const token = req.headers["authorization"]
    const token = req.headers["authorization"]?.replace("Bearer ", "")

    if (!token) {
      throw new UnauthorizedException(
        failureResponse(401, validationMessage(messageKey.invalid_token)),
      )
    }

    // Find the user with this token
    const loggedInUser = await this.authService.getUserByToken(token)

    if (!loggedInUser) {
      throw new UnauthorizedException(
        failureResponse(401, validationMessage(messageKey.invalid_token)),
      )
    }

    // Skip token expiration check for Android and iOS devices
    // Mobile apps should only logout when user explicitly logs out
    const deviceType = loggedInUser.device_type?.toLowerCase()
    const isMobileDevice = deviceType === "android" || deviceType === "ios"

    if (!isMobileDevice) {
      // Only check expiration for web and other devicesj
      const expirationTime = moment(loggedInUser.access_token_expire_at).utc(
        true,
      )
      const currentTime = moment().utc(true)

      // Check if the token has expired
      if (currentTime >= expirationTime) {
        await this.authService.logout(token)
        throw new UnauthorizedException(
          failureResponse(401, validationMessage(messageKey.token_expire)),
        )
      }
    }

    req.user = loggedInUser

    // If all checks pass, return true
    return true
  }
}
