import { getPayload as _getPayload } from "payload";
import type { SanitizedConfig } from "payload";
import type { AuditLogProtocol } from "@repo/core-shared/di";
import type { IDataRectify } from "./data-rectify.interface";
import type { DsrCollectionCustom } from "./dsr-collection-custom";

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>;

/**
 * Payload-backed IDataRectify. Verifies the target field is PII-tagged before
 * updating and emits a RESTRICT audit entry with `reason: "art-16-request"` as
 * the tamper-evident record of the Art. 16 correction.
 */
export class PayloadDataRectify implements IDataRectify {
  constructor(
    private readonly config: SanitizedConfig,
    private readonly auditLog: AuditLogProtocol,
    private readonly getPayloadFn: GetPayload = _getPayload as unknown as GetPayload,
  ) {}

  async updateSubjectField(
    subjectId: string,
    collectionSlug: string,
    field: string,
    value: unknown,
  ): Promise<void> {
    const collectionCfg = this.config.collections.find(
      (c) => c.slug === collectionSlug,
    );
    if (!collectionCfg) {
      throw new Error(`Collection "${collectionSlug}" not found in config`);
    }

    const custom = (collectionCfg.custom ?? {}) as DsrCollectionCustom;
    if (!custom.subject) {
      throw new Error(
        `Collection "${collectionSlug}" has no DSR subject linkage`,
      );
    }
    if (!custom.pii?.[field]) {
      throw new Error(
        `Field "${field}" in "${collectionSlug}" is not tagged as PII`,
      );
    }

    const { field: subjectField } = custom.subject;
    const where =
      subjectField === "id"
        ? { id: { equals: subjectId } }
        : { [subjectField]: { equals: subjectId } };

    const payload = await this.getPayloadFn({ config: this.config });
    const result = await payload.find({
      collection: collectionSlug,
      where,
      overrideAccess: true,
      limit: 1000,
    });

    for (const doc of result.docs) {
      await payload.update({
        collection: collectionSlug,
        id: String(doc["id"]),
        data: { [field]: value },
        overrideAccess: true,
      });
    }

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