/**
 * FeedbackButtons 컴포넌트 단위 테스트
 * 아르고스(테스터) 작성
 *
 * 테스트 대상: FeedbackButtons.tsx
 *  - "정확해요" / "틀렸어요" 버튼 렌더링
 *  - "정확해요" 클릭 → /api/ai/feedback POST (rating: "positive")
 *  - "틀렸어요" 클릭 → 오답 유형 선택 UI 확장
 *  - 제출 완료 후 감사 메시지 표시
 *
 * 환경: jsdom (React 렌더링 필요)
 * 프레임워크: vitest + @testing-library/react
 */

// @vitest-environment jsdom

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import FeedbackButtons from '../FeedbackButtons';

// ── global fetch 모킹 ─────────────────────────────────────────────────────

global.fetch = vi.fn();

// ── 기본 Props ────────────────────────────────────────────────────────────

const defaultProps = {
    queryId: 'test-query-id-001',
    query: '암보험 보장 범위가 어떻게 되나요?',
    answer: '약관 제5조에 따라 암 진단 시 보장됩니다. ※ 출처: A상품 약관 10p',
};

// ── 헬퍼 함수 ─────────────────────────────────────────────────────────────

/** fetch 성공 응답 모킹 */
function mockFetchSuccess() {
    (global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
        new Response(JSON.stringify({ success: true }), { status: 201 })
    );
}

/** fetch 실패 응답 모킹 */
function mockFetchFailure() {
    (global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
        new Response(JSON.stringify({ error: '서버 오류' }), { status: 500 })
    );
}

// ── 테스트 ─────────────────────────────────────────────────────────────────

describe('FeedbackButtons', () => {

    beforeEach(() => {
        vi.clearAllMocks();
    });

    // ----------------------------------------------------------
    // 기본 렌더링
    // ----------------------------------------------------------
    describe('기본 렌더링', () => {
        it('"정확해요" 버튼이 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);
            expect(screen.getByRole('button', { name: /정확해요/i })).toBeDefined();
        });

        it('"틀렸어요" 버튼이 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);
            expect(screen.getByRole('button', { name: /틀렸어요/i })).toBeDefined();
        });

        it('"정확해요", "틀렸어요" 두 버튼이 동시에 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);
            const buttons = screen.getAllByRole('button');
            const labels = buttons.map(b => b.textContent ?? '');
            expect(labels.some(l => l.includes('정확해요'))).toBe(true);
            expect(labels.some(l => l.includes('틀렸어요'))).toBe(true);
        });

        it('초기 상태에서 오답 유형 선택 UI는 표시되지 않는다', () => {
            render(<FeedbackButtons {...defaultProps} />);
            expect(screen.queryByText('면책 누락')).toBeNull();
            expect(screen.queryByText('상품 혼동')).toBeNull();
            expect(screen.queryByText('구버전 참조')).toBeNull();
            expect(screen.queryByText('기타')).toBeNull();
        });
    });

    // ----------------------------------------------------------
    // "정확해요" 클릭 → fetch POST (rating: "positive")
    // ----------------------------------------------------------
    describe('"정확해요" 클릭', () => {
        it('"정확해요" 클릭 → fetch POST가 /api/ai/feedback으로 호출된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /정확해요/i }));

            await waitFor(() => {
                expect(global.fetch).toHaveBeenCalledOnce();
            });

            const [url, options] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0];
            expect(url).toBe('/api/ai/feedback');
            expect(options.method).toBe('POST');
        });

        it('"정확해요" 클릭 → 요청 body에 rating: "positive"가 포함된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /정확해요/i }));

            await waitFor(() => {
                expect(global.fetch).toHaveBeenCalledOnce();
            });

            const [, options] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0];
            const body = JSON.parse(options.body);
            expect(body.rating).toBe('positive');
        });

        it('"정확해요" 클릭 → 요청 body에 queryId가 포함된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /정확해요/i }));

            await waitFor(() => {
                expect(global.fetch).toHaveBeenCalledOnce();
            });

            const [, options] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0];
            const body = JSON.parse(options.body);
            expect(body.queryId).toBe(defaultProps.queryId);
        });

        it('"정확해요" 클릭 후 성공 → 감사 메시지가 표시된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /정확해요/i }));

            await waitFor(() => {
                expect(screen.getByText('피드백 감사합니다!')).toBeDefined();
            });
        });

        it('"정확해요" 클릭 후 성공 → 버튼이 사라진다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /정확해요/i }));

            await waitFor(() => {
                expect(screen.queryByRole('button', { name: /정확해요/i })).toBeNull();
                expect(screen.queryByRole('button', { name: /틀렸어요/i })).toBeNull();
            });
        });

        it('"정확해요" 클릭 후 서버 오류 → 토스트 오류 메시지가 표시된다', async () => {
            mockFetchFailure();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /정확해요/i }));

            await waitFor(() => {
                expect(screen.getByText(/피드백 전송에 실패했습니다/i)).toBeDefined();
            });
        });
    });

    // ----------------------------------------------------------
    // "틀렸어요" 클릭 → 오답 유형 선택 UI 확장
    // ----------------------------------------------------------
    describe('"틀렸어요" 클릭 → 오답 유형 선택 UI', () => {
        it('"틀렸어요" 클릭 → 오답 유형 선택 UI가 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));

            expect(screen.getByText('면책 누락')).toBeDefined();
            expect(screen.getByText('상품 혼동')).toBeDefined();
            expect(screen.getByText('구버전 참조')).toBeDefined();
            expect(screen.getByText('기타')).toBeDefined();
        });

        it('"틀렸어요" 클릭 → 기존 버튼 쌍("정확해요"/"틀렸어요")이 사라진다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));

            expect(screen.queryByRole('button', { name: /정확해요/i })).toBeNull();
        });

        it('"틀렸어요" 클릭 → "어떤 점이 틀렸나요?" 안내 문구가 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));

            expect(screen.getByText('어떤 점이 틀렸나요?')).toBeDefined();
        });

        it('"틀렸어요" 클릭 → 제출 버튼이 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));

            expect(screen.getByRole('button', { name: /제출/i })).toBeDefined();
        });

        it('"틀렸어요" 클릭 → 취소 버튼이 표시된다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));

            expect(screen.getByRole('button', { name: '취소' })).toBeDefined();
        });

        it('"취소" 클릭 → 오답 유형 선택 UI가 닫히고 기본 버튼이 복원된다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));
            fireEvent.click(screen.getByRole('button', { name: '취소' }));

            expect(screen.getByRole('button', { name: /정확해요/i })).toBeDefined();
            expect(screen.getByRole('button', { name: /틀렸어요/i })).toBeDefined();
        });

        it('오답 유형 라디오 버튼 4개(면책 누락, 상품 혼동, 구버전 참조, 기타)가 렌더링된다', () => {
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));

            const radios = screen.getAllByRole('radio');
            expect(radios).toHaveLength(4);
        });
    });

    // ----------------------------------------------------------
    // 오답 유형 선택 후 제출 → 감사 메시지
    // ----------------------------------------------------------
    describe('오답 유형 선택 후 제출 완료', () => {
        it('오답 유형 선택 후 제출 → fetch POST가 /api/ai/feedback으로 호출된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));
            fireEvent.click(screen.getByRole('button', { name: /제출/i }));

            await waitFor(() => {
                expect(global.fetch).toHaveBeenCalledOnce();
            });

            const [url, options] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0];
            expect(url).toBe('/api/ai/feedback');
            expect(options.method).toBe('POST');
        });

        it('오답 유형 제출 → 요청 body에 rating: "negative"가 포함된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));
            fireEvent.click(screen.getByRole('button', { name: /제출/i }));

            await waitFor(() => {
                expect(global.fetch).toHaveBeenCalledOnce();
            });

            const [, options] = (global.fetch as ReturnType<typeof vi.fn>).mock.calls[0];
            const body = JSON.parse(options.body);
            expect(body.rating).toBe('negative');
        });

        it('오답 유형 제출 성공 후 → 감사 메시지가 표시된다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));
            fireEvent.click(screen.getByRole('button', { name: /제출/i }));

            await waitFor(() => {
                expect(screen.getByText('피드백 감사합니다!')).toBeDefined();
            });
        });

        it('오답 유형 제출 성공 후 → 버튼 UI가 모두 사라진다', async () => {
            mockFetchSuccess();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));
            fireEvent.click(screen.getByRole('button', { name: /제출/i }));

            await waitFor(() => {
                expect(screen.queryByRole('button')).toBeNull();
            });
        });

        it('오답 유형 제출 후 서버 오류 → 토스트 오류 메시지가 표시된다', async () => {
            mockFetchFailure();
            render(<FeedbackButtons {...defaultProps} />);

            fireEvent.click(screen.getByRole('button', { name: /틀렸어요/i }));
            fireEvent.click(screen.getByRole('button', { name: /제출/i }));

            await waitFor(() => {
                expect(screen.getByText(/피드백 전송에 실패했습니다/i)).toBeDefined();
            });
        });
    });
});
