import { jest, describe, it, expect, beforeEach, afterEach } from "@jest/globals"
import { Request, Response } from "express"
import {
  optimizationSuccess,
  setOptimizationSuccessDependencies,
  resetOptimizationSuccessDependencies,
} from "../optimiaztion-success"

describe("optimizationSuccess", () => {
  let mockReq: Partial<Request>
  let mockRes: Partial<Response>
  let mockDependencies: any

  beforeEach(() => {
    // Setup response mock
    mockRes = {
      status: jest.fn().mockReturnThis() as jest.MockedFunction<(code: number) => Response>,
      json: jest.fn() as jest.MockedFunction<(body?: any) => Response>,
    }

    // Setup mock dependencies
    mockDependencies = {
      prisma: {
        optimization_events: {
          updateMany: jest.fn() as jest.MockedFunction<(params: any) => Promise<{ count: number }>>,
        },
      },
    }

    setOptimizationSuccessDependencies(mockDependencies)
  })

  afterEach(() => {
    resetOptimizationSuccessDependencies()
    jest.clearAllMocks()
  })

  describe("input validation", () => {
    it("should throw validation error when trace_id is undefined", async () => {
      mockReq = {
        body: {
          is_optimization_found: true,
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should throw validation error when trace_id is null", async () => {
      mockReq = {
        body: {
          trace_id: null,
          is_optimization_found: true,
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should throw validation error when is_optimization_found is undefined", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should throw validation error when is_optimization_found is not a boolean", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: "true",
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should throw validation error when is_optimization_found is null", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: null,
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should throw validation error when both fields are missing", async () => {
      mockReq = {
        body: {},
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should accept valid input with is_optimization_found as true", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: true,
        },
      } as Request

      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 1 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })

    it("should accept valid input with is_optimization_found as false", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: false,
        },
      } as Request

      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 1 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })

    it("should accept empty string trace_id as valid", async () => {
      mockReq = {
        body: {
          trace_id: "",
          is_optimization_found: true,
        },
      } as Request

      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 1 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })
  })

  describe("database operations", () => {
    beforeEach(() => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: true,
        },
      } as Request
    })

    it("should successfully update optimization event", async () => {
      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 1 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockDependencies.prisma.optimization_events.updateMany).toHaveBeenCalledWith({
        where: { trace_id: "test-trace-id" },
        data: { is_optimization_found: true },
      })
      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })

    it("should throw not found error when no optimization event is found", async () => {
      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 0 })

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("not found"),
      })

      expect(mockDependencies.prisma.optimization_events.updateMany).toHaveBeenCalledWith({
        where: { trace_id: "test-trace-id" },
        data: { is_optimization_found: true },
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should handle multiple records updated", async () => {
      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 3 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockDependencies.prisma.optimization_events.updateMany).toHaveBeenCalledWith({
        where: { trace_id: "test-trace-id" },
        data: { is_optimization_found: true },
      })
      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })

    it("should throw internal server error on database error", async () => {
      const error = new Error("Database connection failed")
      mockDependencies.prisma.optimization_events.updateMany.mockRejectedValue(error)

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("Error"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })
  })

  describe("edge cases", () => {
    it("should handle numeric trace_id", async () => {
      mockReq = {
        body: {
          trace_id: 12345,
          is_optimization_found: false,
        },
      } as Request

      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 1 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockDependencies.prisma.optimization_events.updateMany).toHaveBeenCalledWith({
        where: { trace_id: 12345 },
        data: { is_optimization_found: false },
      })
      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })

    it("should handle extra fields in request body", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: true,
          extra_field: "should be ignored",
          another_field: 123,
        },
      } as Request

      mockDependencies.prisma.optimization_events.updateMany.mockResolvedValue({ count: 1 })

      await optimizationSuccess(mockReq as Request, mockRes as Response)

      expect(mockDependencies.prisma.optimization_events.updateMany).toHaveBeenCalledWith({
        where: { trace_id: "test-trace-id" },
        data: { is_optimization_found: true },
      })
      expect(mockRes.status).toHaveBeenCalledWith(200)
      expect(mockRes.json).toHaveBeenCalledWith({ message: "Optimization status updated." })
    })
  })

  describe("type validation edge cases", () => {
    it("should reject is_optimization_found as number 0", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: 0,
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should reject is_optimization_found as number 1", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: 1,
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should reject is_optimization_found as array", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: [],
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })

    it("should reject is_optimization_found as object", async () => {
      mockReq = {
        body: {
          trace_id: "test-trace-id",
          is_optimization_found: {},
        },
      } as Request

      await expect(optimizationSuccess(mockReq as Request, mockRes as Response)).rejects.toMatchObject({
        message: expect.stringContaining("trace_id and is_optimization_found(boolean) are required"),
      })
      expect(mockRes.status).not.toHaveBeenCalled()
    })
  })
})
