/**
 * Command Parser Tests
 */

import { Test, TestingModule } from "@nestjs/testing";
import { describe, it, expect, beforeEach } from "vitest";
import { CommandParserService } from "./command-parser.service";
import { CommandAction } from "./command.interface";

describe("CommandParserService", () => {
  let service: CommandParserService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [CommandParserService],
    }).compile();

    service = module.get<CommandParserService>(CommandParserService);
  });

  describe("parseCommand", () => {
    describe("fix command", () => {
      it("should parse fix command with current repo issue (#42)", () => {
        const result = service.parseCommand("@mosaic fix #42");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.FIX);
          expect(result.command.issue).toEqual({
            number: 42,
          });
        }
      });

      it("should parse fix command with cross-repo issue (owner/repo#42)", () => {
        const result = service.parseCommand("@mosaic fix mosaic/stack#42");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.FIX);
          expect(result.command.issue).toEqual({
            number: 42,
            owner: "mosaic",
            repo: "stack",
          });
        }
      });

      it("should parse fix command with full URL", () => {
        const result = service.parseCommand(
          "@mosaic fix https://git.mosaicstack.dev/mosaic/stack/issues/42"
        );

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.FIX);
          expect(result.command.issue).toEqual({
            number: 42,
            owner: "mosaic",
            repo: "stack",
            url: "https://git.mosaicstack.dev/mosaic/stack/issues/42",
          });
        }
      });

      it("should return error when fix command has no issue reference", () => {
        const result = service.parseCommand("@mosaic fix");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("issue reference");
          expect(result.error.help).toBeDefined();
        }
      });

      it("should return error when fix command has invalid issue reference", () => {
        const result = service.parseCommand("@mosaic fix invalid");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("Invalid issue reference");
        }
      });
    });

    describe("status command", () => {
      it("should parse status command with job ID", () => {
        const result = service.parseCommand("@mosaic status job-123");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.STATUS);
          expect(result.command.jobId).toBe("job-123");
        }
      });

      it("should return error when status command has no job ID", () => {
        const result = service.parseCommand("@mosaic status");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("job ID");
          expect(result.error.help).toBeDefined();
        }
      });
    });

    describe("cancel command", () => {
      it("should parse cancel command with job ID", () => {
        const result = service.parseCommand("@mosaic cancel job-123");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.CANCEL);
          expect(result.command.jobId).toBe("job-123");
        }
      });

      it("should return error when cancel command has no job ID", () => {
        const result = service.parseCommand("@mosaic cancel");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("job ID");
        }
      });
    });

    describe("retry command", () => {
      it("should parse retry command with job ID", () => {
        const result = service.parseCommand("@mosaic retry job-123");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.RETRY);
          expect(result.command.jobId).toBe("job-123");
        }
      });

      it("should return error when retry command has no job ID", () => {
        const result = service.parseCommand("@mosaic retry");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("job ID");
        }
      });
    });

    describe("verbose command", () => {
      it("should parse verbose command with job ID", () => {
        const result = service.parseCommand("@mosaic verbose job-123");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.VERBOSE);
          expect(result.command.jobId).toBe("job-123");
        }
      });

      it("should return error when verbose command has no job ID", () => {
        const result = service.parseCommand("@mosaic verbose");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("job ID");
        }
      });
    });

    describe("quiet command", () => {
      it("should parse quiet command", () => {
        const result = service.parseCommand("@mosaic quiet");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.QUIET);
        }
      });
    });

    describe("help command", () => {
      it("should parse help command", () => {
        const result = service.parseCommand("@mosaic help");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.HELP);
        }
      });
    });

    describe("edge cases", () => {
      it("should handle extra whitespace", () => {
        const result = service.parseCommand("  @mosaic   fix   #42  ");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.FIX);
          expect(result.command.issue?.number).toBe(42);
        }
      });

      it("should be case-insensitive for @mosaic mention", () => {
        const result = service.parseCommand("@Mosaic fix #42");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.FIX);
        }
      });

      it("should be case-insensitive for action", () => {
        const result = service.parseCommand("@mosaic FIX #42");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.action).toBe(CommandAction.FIX);
        }
      });

      it("should return error when message does not start with @mosaic", () => {
        const result = service.parseCommand("fix #42");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("@mosaic");
        }
      });

      it("should return error when no action is provided", () => {
        const result = service.parseCommand("@mosaic ");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("action");
          expect(result.error.help).toBeDefined();
        }
      });

      it("should return error for unknown action", () => {
        const result = service.parseCommand("@mosaic unknown");

        expect(result.success).toBe(false);
        if (!result.success) {
          expect(result.error.message).toContain("Unknown action");
          expect(result.error.help).toBeDefined();
        }
      });
    });

    describe("issue reference parsing", () => {
      it("should parse GitHub-style issue URLs", () => {
        const result = service.parseCommand("@mosaic fix https://github.com/owner/repo/issues/42");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.issue).toEqual({
            number: 42,
            owner: "owner",
            repo: "repo",
            url: "https://github.com/owner/repo/issues/42",
          });
        }
      });

      it("should parse Gitea-style issue URLs", () => {
        const result = service.parseCommand(
          "@mosaic fix https://git.example.com/owner/repo/issues/42"
        );

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.issue).toEqual({
            number: 42,
            owner: "owner",
            repo: "repo",
            url: "https://git.example.com/owner/repo/issues/42",
          });
        }
      });

      it("should handle issue references with leading zeros", () => {
        const result = service.parseCommand("@mosaic fix #042");

        expect(result.success).toBe(true);
        if (result.success) {
          expect(result.command.issue?.number).toBe(42);
        }
      });
    });
  });
});
