import { render, screen, waitFor } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import { ConstitutionalChangePage } from "../pages/ConstitutionalChangePage"
import { toast } from "sonner"

jest.mock("sonner", () => ({
    toast: {
        error: jest.fn(),
        success: jest.fn(),
    },
}))

const mockGetConstitutionalChanges = jest.fn()
jest.mock("@/api/API", () => ({
    API: {
        getConstitutionalChanges: (...args: unknown[]) =>
            mockGetConstitutionalChanges(...args),
        getConstitutionalChangeMeta: jest.fn().mockResolvedValue({
            data: {
                success: true,
                structureTargets: [
                    { value: "Partnership", label: "Partnership" },
                    { value: "LLP", label: "LLP" },
                ],
            },
        }),
        getDealers: jest.fn().mockResolvedValue({
            data: { success: true, data: [] },
        }),
        getOutlets: jest.fn().mockResolvedValue({ data: { outlets: [] } }),
        createConstitutionalChange: jest.fn(),
    },
}))

describe("ConstitutionalChangePage", () => {
    const onViewDetails = jest.fn()

    beforeEach(() => {
        jest.clearAllMocks()
        mockGetConstitutionalChanges.mockResolvedValue({
            data: { success: true, requests: [] },
        })
    })

    function setup() {
        render(<ConstitutionalChangePage onViewDetails={onViewDetails} />)
    }

    it("renders header and stats after loading", async () => {
        setup()

        await waitFor(() => {
            expect(mockGetConstitutionalChanges).toHaveBeenCalled()
        })

        expect(
            screen.getByRole("heading", {
                name: /constitutional change management/i,
            }),
        ).toBeInTheDocument()

        expect(screen.getByText("Total Requests")).toBeInTheDocument()
        expect(
            screen.getAllByText(/Submitted \/ Review/i).length,
        ).toBeGreaterThanOrEqual(1)
        expect(screen.getAllByText(/^Completed$/i).length).toBeGreaterThanOrEqual(
            1,
        )

        expect(
            screen.getByRole("button", { name: /new request/i }),
        ).toBeInTheDocument()
    })

    it("shows empty state when there are no requests", async () => {
        setup()

        await waitFor(() => {
            expect(
                screen.getByText(
                    /no constitutional change requests found/i,
                ),
            ).toBeInTheDocument()
        })
    })

    it("calls onViewDetails when View is clicked for a row", async () => {
        const user = userEvent.setup()
        mockGetConstitutionalChanges.mockResolvedValue({
            data: {
                success: true,
                requests: [
                    {
                        requestId: "CCR-100",
                        status: "Submitted",
                        currentStage: "Submitted",
                        currentConstitution: "Proprietorship",
                        changeType: "Partnership",
                        progressPercentage: 5,
                        createdAt: "2024-06-01T10:00:00.000Z",
                        dealer: {
                            fullName: "Dealer User",
                            dealerProfile: {
                                dealerCode: { dealerCode: "DLR-1" },
                                businessName: "Roadside Motors",
                                registeredAddress: "City",
                            },
                        },
                    },
                ],
            },
        })

        setup()

        const viewBtn = await screen.findByRole("button", { name: /^view$/i })
        await user.click(viewBtn)

        expect(onViewDetails).toHaveBeenCalledWith("CCR-100")
    })

    it("opens New Request dialog and loads form fields", async () => {
        const user = userEvent.setup()
        setup()

        await waitFor(() => {
            expect(mockGetConstitutionalChanges).toHaveBeenCalled()
        })

        await user.click(
            screen.getByRole("button", { name: /new request/i }),
        )

        expect(
            screen.getByRole("heading", {
                name: /create constitutional change request/i,
            }),
        ).toBeInTheDocument()

        expect(screen.getByText(/^Dealer \*$/i)).toBeInTheDocument()
    })

    it("shows backend duplicate-open message on create conflict", async () => {
        const user = userEvent.setup()
        const { API } = await import("@/api/API")
        ;(API.getDealers as jest.Mock).mockResolvedValueOnce({
            data: {
                success: true,
                data: [
                    {
                        user: { id: "dealer-user-1" },
                        constitutionType: "Proprietorship",
                        businessName: "Dealer A",
                        legalName: "Dealer A Pvt",
                        dealerCode: { dealerCode: "DLR-1" },
                    },
                ],
            },
        })
        ;(API.createConstitutionalChange as jest.Mock).mockRejectedValueOnce({
            response: {
                data: {
                    message:
                        "Open constitutional request CCR-1 already exists at ASM Review. Complete it before creating a new one.",
                },
            },
        })

        setup()
        await user.click(screen.getByRole("button", { name: /new request/i }))
        await screen.findByRole("heading", {
            name: /create constitutional change request/i,
        })

        await user.click(screen.getByRole("combobox", { name: /dealer/i }))
        await user.click(await screen.findByText(/DLR-1 — Dealer A/i))

        await user.click(screen.getByRole("combobox", { name: /proposed constitution/i }))
        await user.click(await screen.findByText(/^Partnership$/i))

        const reasonField = screen.getByLabelText(/reason for constitutional change/i)
        await user.type(reasonField, "Need to onboard new partner")

        await user.click(screen.getByRole("button", { name: /submit request/i }))

        await waitFor(() => {
            expect(toast.error).toHaveBeenCalledWith(
                expect.stringContaining("Open constitutional request CCR-1 already exists")
            )
        })
    })
})
