import { and, eq, isNull } from 'drizzle-orm';
import { crmRoleProfiles, memberships } from '@/db/schema';
import { db } from '@/lib/db';
import {
  ALL_PERMISSIONS,
  type CrmApprovalAuthority,
  type CrmOwnershipScope,
  type CrmScopeMode,
  getDefaultBusinessRole,
  getRoleProfileDefinition,
  isApprovalAuthority,
  isMembershipRole,
  isOwnershipScope,
  isScopeMode,
  resolveEffectivePermissions,
  type MembershipRole,
  type Permission,
  type SystemRole
} from './rbac';

export interface ResolvedCrmAccess {
  membershipRole: MembershipRole;
  businessRole: string;
  permissions: Permission[];
  branchScopeIds: string[];
  productTypeScopeIds: string[];
  ownershipScope: CrmOwnershipScope;
  branchScopeMode: CrmScopeMode;
  productScopeMode: CrmScopeMode;
  approvalAuthority: CrmApprovalAuthority;
  roleProfileName: string | null;
}

type BranchScopedAccess = Pick<
  ResolvedCrmAccess,
  'branchScopeMode' | 'branchScopeIds'
> | {
  branchScopeMode: string;
  branchScopeIds: string[];
};

type ProductScopedAccess = Pick<
  ResolvedCrmAccess,
  'productScopeMode' | 'productTypeScopeIds'
> | {
  productScopeMode: string;
  productTypeScopeIds: string[];
};

function normalizeStringArray(value: unknown) {
  return Array.isArray(value)
    ? [...new Set(value.filter((item): item is string => typeof item === 'string' && item.trim().length > 0))]
    : [];
}

export async function resolveCrmMembershipAccess(input: {
  systemRole: SystemRole;
  organizationId: string;
  membership: typeof memberships.$inferSelect;
}): Promise<ResolvedCrmAccess> {
  if (input.systemRole === 'super_admin') {
    return {
      membershipRole: 'admin',
      businessRole: input.membership.businessRole,
      permissions: ALL_PERMISSIONS,
      branchScopeIds: [],
      productTypeScopeIds: [],
      ownershipScope: 'organization',
      branchScopeMode: 'all',
      productScopeMode: 'all',
      approvalAuthority: 'final',
      roleProfileName: 'System Admin'
    };
  }

  const membershipRole = isMembershipRole(input.membership.role)
    ? input.membership.role
    : 'user';
  const businessRole = input.membership.businessRole || getDefaultBusinessRole(membershipRole);
  const [roleProfile] = await db
    .select()
    .from(crmRoleProfiles)
    .where(
      and(
        eq(crmRoleProfiles.organizationId, input.organizationId),
        eq(crmRoleProfiles.code, businessRole),
        eq(crmRoleProfiles.isActive, true),
        isNull(crmRoleProfiles.deletedAt)
      )
    )
    .limit(1);
  const defaultDefinition = getRoleProfileDefinition(businessRole);

  const ownershipScope: CrmOwnershipScope = isOwnershipScope(roleProfile?.ownershipScope ?? '')
    ? (roleProfile.ownershipScope as CrmOwnershipScope)
    : (defaultDefinition?.ownershipScope ?? 'own');
  const branchScopeMode: CrmScopeMode = isScopeMode(roleProfile?.branchScopeMode ?? '')
    ? (roleProfile.branchScopeMode as CrmScopeMode)
    : (defaultDefinition?.branchScopeMode ?? 'assigned');
  const productScopeMode: CrmScopeMode = isScopeMode(roleProfile?.productScopeMode ?? '')
    ? (roleProfile.productScopeMode as CrmScopeMode)
    : (defaultDefinition?.productScopeMode ?? 'assigned');
  const approvalAuthority: CrmApprovalAuthority = isApprovalAuthority(
    roleProfile?.approvalAuthority ?? ''
  )
    ? (roleProfile.approvalAuthority as CrmApprovalAuthority)
    : (defaultDefinition?.approvalAuthority ?? 'none');

  return {
    membershipRole,
    businessRole,
    permissions: resolveEffectivePermissions({
      systemRole: input.systemRole,
      membershipRole,
      businessRole,
      rolePermissions: roleProfile?.permissions ?? defaultDefinition?.permissions ?? [],
      directPermissions: input.membership.permissions
    }),
    branchScopeIds: normalizeStringArray(input.membership.branchScopeIds),
    productTypeScopeIds: normalizeStringArray(input.membership.productTypeScopeIds),
    ownershipScope,
    branchScopeMode,
    productScopeMode,
    approvalAuthority,
    roleProfileName: roleProfile?.name ?? defaultDefinition?.name ?? null
  };
}

export function hasBranchScopeAccess(access: BranchScopedAccess, branchId?: string | null) {
  if (!branchId) {
    return true;
  }

  if (access.branchScopeMode === 'all' || access.branchScopeIds.length === 0) {
    return true;
  }

  return access.branchScopeIds.includes(branchId);
}

export function hasProductScopeAccess(access: ProductScopedAccess, productTypeId?: string | null) {
  if (!productTypeId) {
    return true;
  }

  if (access.productScopeMode === 'all' || access.productTypeScopeIds.length === 0) {
    return true;
  }

  return access.productTypeScopeIds.includes(productTypeId);
}
