import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
import {
  readStoreAllowFromForDmPolicy,
  resolveDmGroupAccessWithLists,
  type DmGroupAccessDecision,
} from "../../security/dm-policy-shared.js";
import { normalizeDiscordAllowList, resolveDiscordAllowListMatch } from "./allow-list.js";

const DISCORD_ALLOW_LIST_PREFIXES = ["discord:", "user:", "pk:"];

export type DiscordDmPolicy = "open" | "pairing" | "allowlist" | "disabled";

export type DiscordDmCommandAccess = {
  decision: DmGroupAccessDecision;
  reason: string;
  commandAuthorized: boolean;
  allowMatch: ReturnType<typeof resolveDiscordAllowListMatch> | { allowed: false };
};

function resolveSenderAllowMatch(params: {
  allowEntries: string[];
  sender: { id: string; name?: string; tag?: string };
  allowNameMatching: boolean;
}) {
  const allowList = normalizeDiscordAllowList(params.allowEntries, DISCORD_ALLOW_LIST_PREFIXES);
  return allowList
    ? resolveDiscordAllowListMatch({
        allowList,
        candidate: params.sender,
        allowNameMatching: params.allowNameMatching,
      })
    : ({ allowed: false } as const);
}

function resolveDmPolicyCommandAuthorization(params: {
  dmPolicy: DiscordDmPolicy;
  decision: DmGroupAccessDecision;
  commandAuthorized: boolean;
}) {
  if (params.dmPolicy === "open" && params.decision === "allow") {
    return true;
  }
  return params.commandAuthorized;
}

export async function resolveDiscordDmCommandAccess(params: {
  accountId: string;
  dmPolicy: DiscordDmPolicy;
  configuredAllowFrom: string[];
  sender: { id: string; name?: string; tag?: string };
  allowNameMatching: boolean;
  useAccessGroups: boolean;
  readStoreAllowFrom?: () => Promise<string[]>;
}): Promise<DiscordDmCommandAccess> {
  const storeAllowFrom = params.readStoreAllowFrom
    ? await params.readStoreAllowFrom().catch(() => [])
    : await readStoreAllowFromForDmPolicy({
        provider: "discord",
        accountId: params.accountId,
        dmPolicy: params.dmPolicy,
      });

  const access = resolveDmGroupAccessWithLists({
    isGroup: false,
    dmPolicy: params.dmPolicy,
    allowFrom: params.configuredAllowFrom,
    groupAllowFrom: [],
    storeAllowFrom,
    isSenderAllowed: (allowEntries) =>
      resolveSenderAllowMatch({
        allowEntries,
        sender: params.sender,
        allowNameMatching: params.allowNameMatching,
      }).allowed,
  });

  const allowMatch = resolveSenderAllowMatch({
    allowEntries: access.effectiveAllowFrom,
    sender: params.sender,
    allowNameMatching: params.allowNameMatching,
  });

  const commandAuthorized = resolveCommandAuthorizedFromAuthorizers({
    useAccessGroups: params.useAccessGroups,
    authorizers: [
      {
        configured: access.effectiveAllowFrom.length > 0,
        allowed: allowMatch.allowed,
      },
    ],
    modeWhenAccessGroupsOff: "configured",
  });

  return {
    decision: access.decision,
    reason: access.reason,
    commandAuthorized: resolveDmPolicyCommandAuthorization({
      dmPolicy: params.dmPolicy,
      decision: access.decision,
      commandAuthorized,
    }),
    allowMatch,
  };
}
