import {
  CONSOLE_USER_SESSION_ID_TOKEN_DEFAULTS,
  CONSOLE_USER_SESSION_TOKEN_DEFAULTS,
} from "@/lib/cookie";
import { error } from "@/lib/response";
import { Context, Next } from "hono";
import { getCookie } from "hono/cookie";
import { ConsoleFeatureRepository } from "../internal/console-features/console-features.repository";
import { ConsoleFeatureServices } from "../internal/console-features/console-features.services";
import { ConsoleUserRolesRepository } from "../internal/console-user-roles/console-user-roles.repository";
import { ConsoleUserRolesServices } from "../internal/console-user-roles/console-user-roles.services";
import { ConsoleUserSessionRepository } from "../internal/console-user-sessions/console-user-session.repository";
import { ConsoleUserSessionServices } from "../internal/console-user-sessions/console-user-session.services";
import { ConsoleUserRepository } from "../internal/console-users/console-users.repository";
import { ConsoleUserServices } from "../internal/console-users/console-users.services";
import { VerificationTokenRepository } from "../internal/verification-tokens/verification-tokens.repository";
import { VerificationTokenServices } from "../internal/verification-tokens/verification-tokens.services";

type AdminAccessFeatureType =
  | "members"
  | "bookings"
  | "membership-clubs"
  | "account-types"
  | "charge-centers"
  | "user-management"
  | "role-management"
  | "account-status"
  | "notifications"
  | "promo-codes"
  | "chatbot-agents"
  | "chatbot-prompts"
  | "admin-logs"
  | "hot-deals"
  | "edm"
  | "promo-code-campaigns"
  | "resorts"
  | "member-offers"
  | "dashboard"
  | "campaign-reports"
  | "promocode-access-list"
  | "travel-rules"
  | "kcgm"
  | "event-analytics"
  // Who may hand out member-module access (roles + per-user grants). Separate
  // from role-management: console features and member data access are different
  // things to be able to give away.
  | "member-access-list";
// NOTE: the member module deliberately has no sub-feature slugs. Role
// management grants "members"; everything inside it is decided by
// `console_user_member_access` — see middlewares/withMemberAccess.ts.
type AdminAccessPrivilegeType = "create" | "read" | "update" | "delete";

export const withConsoleUserRole =
  (feature: AdminAccessFeatureType, privilegeType: AdminAccessPrivilegeType) =>
  async (ctx: Context, next: Next) => {
    const consoleUserSessionServices = ConsoleUserSessionServices({
      ConsoleUserSessionRepository: ConsoleUserSessionRepository(ctx),
    });
    const consoleFeatureServices = ConsoleFeatureServices({
      ConsoleFeatureRepository: ConsoleFeatureRepository(ctx),
    });
    const consoleUserRolesServices = ConsoleUserRolesServices({
      ConsoleUserRolesRepository: ConsoleUserRolesRepository(ctx),
    });
    const verificationTokenServices = VerificationTokenServices({
      VerificationTokenRepository: VerificationTokenRepository(ctx),
    });
    const consoleUserServices = ConsoleUserServices({
      ConsoleUserRepository: ConsoleUserRepository(ctx),
      ConsoleUserRolesServices: consoleUserRolesServices,
      ConsoleUserSessionServices: consoleUserSessionServices,
      VerificationTokenServices: verificationTokenServices,
    });
    const admin_session = getCookie(
      ctx,
      CONSOLE_USER_SESSION_TOKEN_DEFAULTS.name,
    );
    const admin_session_id = getCookie(
      ctx,
      CONSOLE_USER_SESSION_ID_TOKEN_DEFAULTS.name,
    );
    if (!admin_session || !admin_session_id) {
      return error(ctx, "Unauthorized Access", 401);
    }

    const consoleUserSession =
      await consoleUserSessionServices.GetUserSession(admin_session_id);
    if (!consoleUserSession) {
      return error(ctx, "Unauthorized Access", 401);
    }

    const user = await consoleUserServices.GetUserById(
      consoleUserSession.consoleUserRecord.id,
    );

    if (user.is_super_admin) {
      return await next();
    }

    // Find the feature using feature param
    const featureRecord =
      await consoleFeatureServices.FindFeatureBySlug(feature);
    if (!featureRecord) {
      return error(
        ctx,
        "You do not have permission to access this feature",
        403,
      );
    }

    if (user.roles?.length === 0) {
      return error(
        ctx,
        "You do not have permission to access this feature",
        403,
      );
    }
    for (const ur of user.roles) {
      for (const privilege of ur.privileges) {
        if (
          privilege.console_feature_id === featureRecord.id &&
          privilege[privilegeType]
        ) {
          return await next();
        }
      }
    }
    return error(ctx, "You do not have permission to access this feature", 403);
  };
