import { getPayload as _getPayload } from "payload";
import type { SanitizedConfig } from "payload";
import type { AuditLogProtocol } from "@repo/core-shared/di";
import type { IProcessingRestriction } from "./processing-restriction.interface";

type PayloadDoc = Record<string, unknown>;

type PayloadAPI = {
  find(args: {
    collection: string;
    where: Record<string, unknown>;
    overrideAccess: true;
    limit: number;
  }): Promise<{ docs: PayloadDoc[] }>;
  update(args: {
    collection: string;
    id: string;
    data: Record<string, unknown>;
    overrideAccess: true;
  }): Promise<PayloadDoc>;
};

type GetPayload = (args: { config: SanitizedConfig }) => Promise<PayloadAPI>;

const USERS_COLLECTION = "users";
const RESTRICTION_FIELD = "processingRestrictedAt";

/**
 * Payload-backed IProcessingRestriction. Toggles and reads the
 * `processingRestrictedAt` date field on the subject's user record.
 *
 * Emits RESTRICT or UNRESTRICT audit entries on every state change.
 * The `subjectId` is the document ID in the `users` collection.
 */
export class PayloadProcessingRestriction implements IProcessingRestriction {
  constructor(
    private readonly config: SanitizedConfig,
    private readonly auditLog: AuditLogProtocol,
    private readonly getPayloadFn: GetPayload = _getPayload as unknown as GetPayload,
  ) {}

  async setRestriction(subjectId: string, granted: boolean): Promise<void> {
    const payload = await this.getPayloadFn({ config: this.config });

    await payload.update({
      collection: USERS_COLLECTION,
      id: subjectId,
      data: { [RESTRICTION_FIELD]: granted ? new Date().toISOString() : null },
      overrideAccess: true,
    });

    await this.auditLog.record({
      actorId: subjectId,
      actorType: "user",
      actorRoles: [],
      action: granted ? "RESTRICT" : "UNRESTRICT",
      resource: { type: USERS_COLLECTION, id: subjectId },
      changedFields: [RESTRICTION_FIELD],
      at: new Date(),
      scope: {
        feature: "core-dsr",
        environment: process.env["NODE_ENV"] ?? "development",
        tenant: "default",
      },
      from: { ipTruncated: "system", userAgent: "system" },
      containsPii: false,
      outcome: "success",
    });
  }

  async isRestricted(subjectId: string): Promise<boolean> {
    const payload = await this.getPayloadFn({ config: this.config });

    const result = await payload.find({
      collection: USERS_COLLECTION,
      where: { id: { equals: subjectId } },
      overrideAccess: true,
      limit: 1,
    });

    const doc = result.docs[0];
    if (!doc) return false;

    const restrictedAt = doc[RESTRICTION_FIELD];
    return restrictedAt !== null && restrictedAt !== undefined;
  }
}
