import { ApiTriggerType } from '../../index.js';
import { GroupBrief } from '../group/index.js';
import { ApplicationUserStatus } from '../user/index.js';

export enum OrganizationRbacAction {
  MANAGE = 'manage'
}

export enum RbacAction {
  READ = 'read',
  CREATE = 'create',
  UPDATE = 'update',
  DELETE = 'delete',
  DEPLOY = 'deploy',
  SHARE = 'share',
  BUILD = 'build',
  EXECUTE = 'execute',
  RESET = 'reset'
}

export enum GroupRbacAction {
  READ = 'read',
  DELETE = 'delete',
  UPDATE = 'update'
}

export enum RbacRole {
  VIEWER = 'viewer',
  BUILDER = 'builder',
  CONFIGURATOR = 'configurator',
  OWNER = 'owner',
  NONE = 'none',
  EXECUTOR = 'executor' // for app api
}

// used when querying permissions (roles table)
export enum PermissionedEntities {
  APPLICATION = 'application',
  APPLICATION_V2 = 'application_v2',
  API_V3 = 'api_v3',
  API = 'api',
  ORGANIZATION = 'organization',
  /**
   * @deprecated The Datasource entity is being deprecated in favor of the Integration entity.
   */
  DATASOURCE = 'datasource',
  INTEGRATION = 'integration',
  SECRET_STORE = 'secret_store'
}

// used in representation layer
export enum PermissionEntityType {
  APPLICATION = 'application',
  APPLICATION_V2 = 'application_v2',
  WORKFLOW = 'workflow',
  SCHEDULED_JOB = 'scheduled_job',
  /**
   * @deprecated The Datasource entity is being deprecated in favor of the Integration entity.
   */
  DATASOURCE = 'datasource',
  INTEGRATION = 'integration'
}

type BaseShareEntryDto = {
  id: string;
  role: RbacRole;
  name: string;
  actorId: string;
};

export type UserShareEntryDto = BaseShareEntryDto & {
  type: 'user';
  email: string;
  status: ApplicationUserStatus;
};

export type GroupShareEntryDto = BaseShareEntryDto & {
  type: 'group';
  size?: number;
};

export type ShareEntryDto = UserShareEntryDto | GroupShareEntryDto;

export const isUserShareEntry = (shareEntry: ShareEntryDto): shareEntry is UserShareEntryDto => shareEntry.type === 'user';
export const isGroupShareEntry = (shareEntry: ShareEntryDto): shareEntry is GroupShareEntryDto => shareEntry.type === 'group';

// When creating a new share entry, we might not have the user ID yet.
export type ShareEntryCreationDto = {
  // lookupId is either an email address or a group ID.
  lookupId: string;
  type: 'user' | 'group';
  role: RbacRole;
};

type BasePermissionEntity = {
  id: string;
  type: PermissionEntityType;
  name: string;
};

export type ApplicationEntity = BasePermissionEntity;

export type WorkflowEntity = BasePermissionEntity;
type JobEntity = BasePermissionEntity;
/**
 * @deprecated The Datasource entity is being deprecated in favor of the Integration entity.
 */
type DatasourceEntity = BasePermissionEntity;
export type IntegrationEntity = BasePermissionEntity;

export type PermissionEntity = ApplicationEntity | WorkflowEntity | JobEntity | DatasourceEntity | IntegrationEntity;

// Entity is referring to application, workflow, or job.
export type EntityPermissionsDto = {
  entity: PermissionEntity;
  permissions: ShareEntryDto[];
};

// RBAC V2 lives below here

export enum AssignmentTypeEnum {
  ROLE = 'role',
  PERMISSION = 'permission'
}

export enum PrincipalTypeEnum {
  GROUP = 'group',
  USER = 'user'
  // ORGANIZATION = 'organization',
  // API_KEY = 'api_key'
}

export enum ResourceTypeEnum {
  ACCESS_TOKENS = 'access_tokens',
  AGENTS = 'agents',
  APPLICATIONS = 'apps',
  APPLICATIONS_APIS = 'apps.apis',
  APPLICATIONS_PAGES = 'apps.pages',
  BILLING = 'billing',
  FOLDERS = 'folders',
  GROUPS = 'groups',
  GROUPS_MEMBERS = 'groups.members',
  INTEGRATIONS = 'integrations',
  LOGS = 'logs',
  LOGS_STREAMS = 'logs.streams',
  ORGANIZATION = 'org',
  // ORGANIZATION_REQUESTS = 'org.requests',
  ORGANIZATION_USERS = 'org.users',
  ORG_KNOWLEDGE = 'org_knowledge',
  PROFILES = 'profiles',
  REPOSITORIES = 'repos',
  ROLES = 'roles',
  SCHEDULED_JOBS = 'jobs',
  SECRETS_STORES = 'secrets_stores',
  WORKFLOWS = 'workflows'
}

// TODO(@taha-au) proj:rbac Add back the commented out role types once they are implemented
// in the system.
export enum RoleTypeEnum {
  APPLICATIONS = 'apps',
  // GROUPS = 'groups',
  INTEGRATIONS = 'integrations',
  ORGANIZATION = 'org', // This represents a role that can contain permissions across resource type boundaries, to be used for organization-wide roles.
  // PROFILES = 'profiles',
  SCHEDULED_JOBS = 'jobs',
  // SECRETS_STORES = 'secrets_stores',
  WORKFLOWS = 'workflows'
}

export enum ActionTypeEnum {
  BUILD = 'build',
  CREATE = 'create',
  DELETE = 'delete',
  DEPLOY = 'deploy',
  MANAGE = 'manage',
  MANAGE_SCHEDULE = 'manage_schedule',
  MANAGE_VISIBILITY = 'manage_visibility',
  PREVIEW = 'preview',
  READ = 'read',
  RUN = 'run',
  SHARE = 'share',
  UPDATE = 'update',
  VIEW = 'view'
}

export const ActionTypeByResourceType = {
  AGENTS: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  BILLING: {
    MANAGE: ActionTypeEnum.MANAGE
  },
  WORKFLOWS: {
    DEPLOY: ActionTypeEnum.DEPLOY,
    DELETE: ActionTypeEnum.DELETE,
    CREATE: ActionTypeEnum.CREATE,
    UPDATE: ActionTypeEnum.UPDATE,
    SHARE: ActionTypeEnum.SHARE
  },
  SECRET_STORES: {
    DELETE: ActionTypeEnum.DELETE,
    CREATE: ActionTypeEnum.CREATE,
    UPDATE: ActionTypeEnum.UPDATE,
    SHARE: ActionTypeEnum.SHARE,
    BUILD: ActionTypeEnum.BUILD
  },
  ROLE_MEMBERS: {
    MANAGE: ActionTypeEnum.MANAGE,
    READ: ActionTypeEnum.READ
  },
  PROFILES: {
    MANAGE: ActionTypeEnum.MANAGE
  },
  ROLES: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  REPOS: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  GROUPS: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  GROUP_MEMBERS: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  ORGANIZATION: {
    MANAGE: ActionTypeEnum.MANAGE,
    READ: ActionTypeEnum.READ
  },
  ORGANIZATION_USERS: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  ACCESS_TOKENS: {
    READ: ActionTypeEnum.READ,
    MANAGE: ActionTypeEnum.MANAGE
  },
  APPLICATIONS: {
    CREATE: ActionTypeEnum.CREATE,
    DELETE: ActionTypeEnum.DELETE,
    DEPLOY: ActionTypeEnum.DEPLOY,
    MANAGE_VISIBILITY: ActionTypeEnum.MANAGE_VISIBILITY,
    PREVIEW: ActionTypeEnum.PREVIEW,
    SHARE: ActionTypeEnum.SHARE,
    UPDATE: ActionTypeEnum.UPDATE,
    VIEW: ActionTypeEnum.VIEW
  },
  FOLDERS: {
    MANAGE: ActionTypeEnum.MANAGE
  },
  INTEGRATIONS: {
    CREATE: ActionTypeEnum.CREATE,
    DELETE: ActionTypeEnum.DELETE,
    BUILD: ActionTypeEnum.BUILD,
    SHARE: ActionTypeEnum.SHARE,
    UPDATE: ActionTypeEnum.UPDATE
  },
  LOGS: {
    READ: ActionTypeEnum.READ
  },
  LOGS_STREAMS: {
    MANAGE: ActionTypeEnum.MANAGE,
    READ: ActionTypeEnum.READ
  },
  SCHEDULED_JOBS: {
    CREATE: ActionTypeEnum.CREATE,
    DELETE: ActionTypeEnum.DELETE,
    DEPLOY: ActionTypeEnum.DEPLOY,
    MANAGE_SCHEDULE: ActionTypeEnum.MANAGE_SCHEDULE,
    RUN: ActionTypeEnum.RUN,
    SHARE: ActionTypeEnum.SHARE,
    UPDATE: ActionTypeEnum.UPDATE
  },
  ORG_KNOWLEDGE: {
    CREATE: ActionTypeEnum.CREATE,
    UPDATE: ActionTypeEnum.UPDATE,
    DELETE: ActionTypeEnum.DELETE
  }
} as const;

type ResourceBrief = {
  id: string;
  name: string;
};

export type AssignmentDto = {
  id: string;
  created: Date;
  assignmentId: string;
  assignmentType: AssignmentTypeEnum;
  principalId: string;
  principalType: PrincipalTypeEnum;
  resourceId: string;
  resourceType: ResourceTypeEnum;
  // role and permission maps to assignmentId in the model
  // that means we will either have role or permission in this object
  role?: RoleDto;
  permission?: PermissionDto;
  // group and user maps to principalId in the model
  // that means we will either have group or user in this object
  group?: GroupBrief;
  user?: {
    id: string;
    name: string;
    email: string;
    status: ApplicationUserStatus;
  };
  api?: ResourceBrief & { triggerType: ApiTriggerType };
  application?: ResourceBrief & { devEnvEnabled: boolean };
  integration?: ResourceBrief;
};

export type RoleDto = {
  id: string;
  name: string;
  description: string;
  type: RoleTypeEnum;
  organizationId: string | null;
  permissions?: PermissionDto[];
};

export type PermissionDto = {
  id: string;
  actionType: ActionTypeEnum;
  resourceType: ResourceTypeEnum;
  description: string;
};

export type SimplePermissionDto = {
  actionType: ActionTypeEnum;
  resourceType: ResourceTypeEnum;
};

export type ResourcePermissions = {
  permissions: ActionTypeEnum[];
};

export class RoleSettingsDto {
  [RoleTypeEnum.ORGANIZATION]?: {
    new_user?: string | null;
  };

  [RoleTypeEnum.APPLICATIONS]?: {
    base?: string | null;
    creator?: string | null;
  };

  /*[RoleTypeEnum.GROUPS]?: {
    base?: string | null;
    creator?: string | null;
  };*/

  [RoleTypeEnum.INTEGRATIONS]?: {
    base?: string | null;
    creator?: string | null;
  };

  [RoleTypeEnum.SCHEDULED_JOBS]?: {
    base?: string | null;
    creator?: string | null;
  };

  [RoleTypeEnum.WORKFLOWS]?: {
    base?: string | null;
    creator?: string | null;
  };

  constructor(
    defaultRoles: {
      roleId: string | null;
      roleType: RoleTypeEnum;
      settingType: ResourceSettingType;
    }[]
  ) {
    for (const roleSetting of defaultRoles) {
      const roleType = roleSetting.roleType;
      const settingType = roleSetting.settingType;
      if (!this[roleType]) {
        this[roleType] = {};
      }
      this[roleType]![settingType] = roleSetting.roleId;
    }
  }
}

export enum ResourceSettingType {
  NEW_USER = 'new_user',
  BASE = 'base',
  CREATOR = 'creator'
}

export type CreatorDto = {
  id: string;
  email: string;
  name: string;
};
