import { describe, test, expect } from "bun:test";
import {
  jiraWebhookSchema,
  jiraIssueResponseSchema,
  jiraSearchResponseSchema,
  jiraProjectSearchResponseSchema,
  jiraChildrenResponseSchema,
} from "@/jira/schemas.js";

import webhookFixture from "./fixtures/webhook-issue-updated.json";
import issueFull from "./fixtures/issue-full.json";
import issueMinimal from "./fixtures/issue-minimal.json";
import searchFixture from "./fixtures/search-results.json";
import projectSearchFixture from "./fixtures/project-search-results.json";
import childrenFixture from "./fixtures/children-list.json";

// ── jiraWebhookSchema ───────────────────────────────────

describe("jiraWebhookSchema", () => {
  test("parses a valid webhook payload", () => {
    const result = jiraWebhookSchema.parse(webhookFixture);
    expect(result.webhookEvent).toBe("jira:issue_updated");
    expect(result.issue.key).toBe("HU-137");
    expect(result.issue.fields.summary).toBe("Login page throws 500 on invalid email format");
  });

  test("parses with description set to null (minimum valid)", () => {
    const minimal = {
      webhookEvent: "jira:issue_created",
      issue: {
        id: "10001",
        key: "HU-1",
        fields: {
          issuetype: { name: "Task" },
          status: { name: "Open" },
          summary: "Minimal webhook",
          description: null,
        },
      },
    };
    const result = jiraWebhookSchema.parse(minimal);
    expect(result.issue.fields.description).toBeNull();
  });

  test("rejects payload missing webhookEvent", () => {
    const bad = {
      issue: {
        id: "10001",
        key: "HU-1",
        fields: {
          issuetype: { name: "Task" },
          status: { name: "Open" },
          summary: "Missing event",
          description: null,
        },
      },
    };
    const result = jiraWebhookSchema.safeParse(bad);
    expect(result.success).toBe(false);
    if (!result.success) {
      expect(result.error.issues.some((i) => i.path.includes("webhookEvent"))).toBe(true);
    }
  });
});

// ── jiraIssueResponseSchema ─────────────────────────────

describe("jiraIssueResponseSchema", () => {
  test("parses a full issue with all optional fields", () => {
    const result = jiraIssueResponseSchema.parse(issueFull);
    expect(result.key).toBe("HU-204");
    expect(result.fields.summary).toBe("Add retry logic to payment webhook handler");
    expect(result.fields.assignee?.displayName).toBe("Julian Dev");
    expect(result.fields.parent?.key).toBe("HU-100");
    expect(result.fields.subtasks).toHaveLength(1);
    expect(result.fields.attachment).toHaveLength(1);
    expect(result.fields.comment?.comments).toHaveLength(1);
    expect(result.fields.components).toHaveLength(2);
    expect(result.fields.customfield_10035).toBe(5);
  });

  test("parses a minimal issue and populates defaults", () => {
    const result = jiraIssueResponseSchema.parse(issueMinimal);
    expect(result.key).toBe("HU-310");
    expect(result.fields.description).toBeNull();
    // Optional fields absent -> defaults
    expect(result.fields.subtasks).toEqual([]);
    expect(result.fields.attachment).toEqual([]);
    expect(result.fields.components).toEqual([]);
    expect(result.fields.assignee).toBeUndefined();
    // userSchema defaults displayName to "Unknown" when omitted
    const withBareAssignee = {
      ...issueMinimal,
      fields: { ...issueMinimal.fields, assignee: { accountId: "xyz789" } },
    };
    const withAssignee = jiraIssueResponseSchema.parse(withBareAssignee);
    expect(withAssignee.fields.assignee?.displayName).toBe("Unknown");
    expect(result.fields.parent).toBeUndefined();
    expect(result.fields.comment).toBeUndefined();
    expect(result.fields.created).toBeUndefined();
    expect(result.fields.customfield_10035).toBeUndefined();
  });

  test("rejects issue missing key", () => {
    const bad = {
      id: "10001",
      fields: {
        summary: "No key",
        description: null,
        issuetype: { name: "Bug" },
        status: { name: "Open" },
      },
    };
    const result = jiraIssueResponseSchema.safeParse(bad);
    expect(result.success).toBe(false);
    if (!result.success) {
      expect(result.error.issues.some((i) => i.path.includes("key"))).toBe(true);
    }
  });
});

// ── jiraSearchResponseSchema ────────────────────────────

describe("jiraSearchResponseSchema", () => {
  test("parses search results with issues", () => {
    const result = jiraSearchResponseSchema.parse(searchFixture);
    expect(result.total).toBe(2);
    expect(result.issues).toHaveLength(2);
    expect(result.issues[0]!.key).toBe("HU-137");
    expect(result.issues[1]!.fields.assignee).toBeNull();
  });

  test("parses minimal search (empty issues, no total)", () => {
    const minimal = { issues: [] };
    const result = jiraSearchResponseSchema.parse(minimal);
    expect(result.total).toBe(0);
    expect(result.issues).toEqual([]);
  });

  test("rejects search missing issues array", () => {
    const bad = { total: 5 };
    const result = jiraSearchResponseSchema.safeParse(bad);
    expect(result.success).toBe(false);
    if (!result.success) {
      expect(result.error.issues.some((i) => i.path.includes("issues"))).toBe(true);
    }
  });
});

// ── jiraProjectSearchResponseSchema ─────────────────────

describe("jiraProjectSearchResponseSchema", () => {
  test("parses project search with all fields", () => {
    const result = jiraProjectSearchResponseSchema.parse(projectSearchFixture);
    expect(result.total).toBe(3);
    expect(result.isLast).toBe(true);
    expect(result.values).toHaveLength(3);
    expect(result.values[0]!.key).toBe("HU");
    expect(result.values[0]!.name).toBe("HuAgent Core");
  });

  test("parses minimal project search with defaults", () => {
    const minimal = { values: [] };
    const result = jiraProjectSearchResponseSchema.parse(minimal);
    expect(result.startAt).toBe(0);
    expect(result.maxResults).toBe(50);
    expect(result.total).toBe(0);
    expect(result.isLast).toBeUndefined();
    expect(result.values).toEqual([]);
  });

  test("rejects project search missing values array", () => {
    const bad = { startAt: 0, maxResults: 50, total: 0 };
    const result = jiraProjectSearchResponseSchema.safeParse(bad);
    expect(result.success).toBe(false);
    if (!result.success) {
      expect(result.error.issues.some((i) => i.path.includes("values"))).toBe(true);
    }
  });
});

// ── jiraChildrenResponseSchema ──────────────────────────

describe("jiraChildrenResponseSchema", () => {
  test("parses children list with parent references", () => {
    const result = jiraChildrenResponseSchema.parse(childrenFixture);
    expect(result.issues).toHaveLength(2);
    expect(result.issues[0]!.key).toBe("HU-205");
    expect(result.issues[0]!.fields.parent?.key).toBe("HU-204");
  });

  test("parses children with optional parent absent", () => {
    const minimal = {
      issues: [
        {
          id: "10300",
          key: "HU-400",
          fields: {
            summary: "Orphan subtask",
            issuetype: { name: "Sub-task" },
            status: { name: "Open" },
          },
        },
      ],
    };
    const result = jiraChildrenResponseSchema.parse(minimal);
    expect(result.issues[0]!.fields.parent).toBeUndefined();
  });

  test("rejects child missing summary", () => {
    const bad = {
      issues: [
        {
          id: "10300",
          key: "HU-400",
          fields: {
            issuetype: { name: "Sub-task" },
            status: { name: "Open" },
          },
        },
      ],
    };
    const result = jiraChildrenResponseSchema.safeParse(bad);
    expect(result.success).toBe(false);
    if (!result.success) {
      expect(result.error.issues.some((i) => i.path.includes("summary"))).toBe(true);
    }
  });
});

// ── Unknown-field stripping ─────────────────────────────

describe("unknown-field stripping", () => {
  test("jiraWebhookSchema strips unknown top-level fields", () => {
    const withExtra = { ...webhookFixture, __extra_field: "ignored" };
    const result = jiraWebhookSchema.parse(withExtra) as Record<string, unknown>;
    expect(result.__extra_field).toBeUndefined();
  });

  test("jiraIssueResponseSchema strips unknown nested fields", () => {
    const fields = issueFull.fields as Record<string, unknown>;
    const patched = {
      ...issueFull,
      fields: { ...fields, __secret: "should be gone" },
    };
    const result = jiraIssueResponseSchema.parse(patched);
    const fieldsRaw = result.fields as Record<string, unknown>;
    expect(fieldsRaw.__secret).toBeUndefined();
  });
});
