import { afterEach, describe, expect, it } from "vitest";
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);
const mock = require("mock-require");

const graphqlRequestModuleId = require.resolve("graphql-request");
const queriesModuleId = require.resolve("../graphql-client/queries");
const rrLoggerModuleId = require.resolve("./rr-logger-event");
const rrExportLogsModuleId = require.resolve("./rr-export-logs");

const loadExportLogs = ({ requests }) => {
  mock.stopAll();

  mock(graphqlRequestModuleId, {
    GraphQLClient: class MockGraphQLClient {
      constructor(endpoint) {
        this.endpoint = endpoint;
        this.headers = {};
      }

      setHeaders(headers) {
        this.headers = headers;
        return this;
      }

      async request(query, variables) {
        requests.push({
          endpoint: this.endpoint,
          headers: this.headers,
          query,
          variables
        });
        return {};
      }
    }
  });

  mock(queriesModuleId, {
    INSERT_EXPORT_LOG: "INSERT_EXPORT_LOG",
    MARK_JOB_EXPORTED: "MARK_JOB_EXPORTED"
  });

  mock(rrLoggerModuleId, () => {});

  delete require.cache[rrExportLogsModuleId];
  return require(rrExportLogsModuleId);
};

const socket = {
  data: { authToken: "socket-token" },
  user: { email: "tech@example.com" }
};

const job = {
  id: "job-1",
  bodyshop: {
    id: "bodyshop-1",
    md_ro_statuses: {
      default_exported: "Exported"
    }
  }
};

describe("server/rr/rr-export-logs", () => {
  const originalEndpoint = process.env.GRAPHQL_ENDPOINT;

  afterEach(() => {
    mock.stopAll();
    delete require.cache[rrExportLogsModuleId];
    process.env.GRAPHQL_ENDPOINT = originalEndpoint;
  });

  it("marks Reynolds full exports as exported using the shared DMS export mutation", async () => {
    process.env.GRAPHQL_ENDPOINT = "https://graphql.example.test/v1/graphql";
    const requests = [];
    const { markRRExportSuccess } = loadExportLogs({ requests });

    await markRRExportSuccess({
      socket,
      jobId: job.id,
      job,
      bodyshop: job.bodyshop,
      result: {
        success: true,
        roStatus: {
          status: "SUCCESS",
          statusCode: "0",
          message: "Finalized"
        }
      },
      metaExtra: {
        rrPreview: {
          provider: "rr",
          previewFormat: "rr-rogog-preview.v1",
          rogg: {
            rows: [{ jobNo: "1", opCode: "BODY", custPrice: "125.00", dlrCost: "50.00" }]
          }
        }
      }
    });

    expect(requests).toHaveLength(1);
    expect(requests[0]).toMatchObject({
      endpoint: "https://graphql.example.test/v1/graphql",
      headers: { Authorization: "Bearer socket-token" },
      query: "MARK_JOB_EXPORTED",
      variables: {
        jobId: "job-1",
        job: {
          status: "Exported",
          date_exported: expect.any(Date)
        },
        log: {
          bodyshopid: "bodyshop-1",
          jobid: "job-1",
          successful: true,
          useremail: "tech@example.com",
          metadata: {
            provider: "rr",
            rrPreview: {
              provider: "rr",
              previewFormat: "rr-rogog-preview.v1",
              rogg: {
                rows: [{ jobNo: "1", opCode: "BODY", custPrice: "125.00", dlrCost: "50.00" }]
              }
            }
          }
        },
        bill: {
          exported: true,
          exported_at: expect.any(Date)
        }
      }
    });
  });

  it("uses the separately loaded bodyshop statuses when job.bodyshop is missing", async () => {
    process.env.GRAPHQL_ENDPOINT = "https://graphql.example.test/v1/graphql";
    const requests = [];
    const { markRRExportSuccess } = loadExportLogs({ requests });

    await markRRExportSuccess({
      socket,
      jobId: job.id,
      job: { id: job.id },
      bodyshop: job.bodyshop,
      result: {
        success: true,
        roStatus: {
          status: "SUCCESS",
          statusCode: "0",
          message: "Finalized"
        }
      }
    });

    expect(requests).toHaveLength(1);
    expect(requests[0]).toMatchObject({
      query: "MARK_JOB_EXPORTED",
      variables: {
        jobId: "job-1",
        job: {
          status: "Exported",
          date_exported: expect.any(Date)
        },
        log: {
          bodyshopid: "bodyshop-1",
          jobid: "job-1",
          successful: true,
          useremail: "tech@example.com"
        }
      }
    });
  });

  it("does not mark Reynolds early RO creation as exported", async () => {
    process.env.GRAPHQL_ENDPOINT = "https://graphql.example.test/v1/graphql";
    const requests = [];
    const { markRRExportSuccess } = loadExportLogs({ requests });

    await markRRExportSuccess({
      socket,
      jobId: job.id,
      job,
      bodyshop: job.bodyshop,
      result: { success: true },
      isEarlyRo: true
    });

    expect(requests).toHaveLength(1);
    expect(requests[0]).toMatchObject({
      query: "INSERT_EXPORT_LOG",
      variables: {
        logs: [
          {
            bodyshopid: "bodyshop-1",
            jobid: "job-1",
            successful: true,
            useremail: "tech@example.com"
          }
        ]
      }
    });
  });
});
