package com.owrawww.controller;

import com.owrawww.service.InquiryService;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.transaction.TransactionFactory;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@Import(InquiryControllerTest.MybatisTestConfig.class)
@WebMvcTest(value = InquiryController.class, excludeAutoConfiguration = MybatisAutoConfiguration.class)
class InquiryControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private InquiryService inquiryService;

    @Test
    @DisplayName("GET /sub04_02 - 문의 폼 페이지 정상 응답")
    void inquiryForm_returnsView() throws Exception {
        mockMvc.perform(get("/sub04_02"))
                .andExpect(status().isOk())
                .andExpect(view().name("sub04_02"));
    }

    @Test
    @DisplayName("POST /sub04_02 - 유효한 입력 시 성공 응답")
    void inquirySubmit_validInput_returnsSuccess() throws Exception {
        given(inquiryService.submit(any())).willReturn(true);

        mockMvc.perform(post("/sub04_02")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .param("name",          "홍길동")
                        .param("email",         "hong@example.com")
                        .param("tel",           "010-1234-5678")
                        .param("dept",          "개발팀")
                        .param("title",         "도입 문의")
                        .param("content",       "서비스 도입 관련 문의드립니다.")
                        .param("solutionGubun", "PG"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true));
    }

    @Test
    @DisplayName("POST /sub04_02 - 이름 누락 시 400 Bad Request")
    void inquirySubmit_missingName_returnsBadRequest() throws Exception {
        mockMvc.perform(post("/sub04_02")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .param("email",         "hong@example.com")
                        .param("tel",           "010-1234-5678")
                        .param("dept",          "개발팀")
                        .param("title",         "도입 문의")
                        .param("content",       "서비스 도입 관련 문의드립니다."))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false));
    }

    @Test
    @DisplayName("POST /sub04_02 - 이메일 형식 오류 시 400 Bad Request")
    void inquirySubmit_invalidEmail_returnsBadRequest() throws Exception {
        mockMvc.perform(post("/sub04_02")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .param("name",    "홍길동")
                        .param("email",   "not-an-email")
                        .param("tel",     "010-1234-5678")
                        .param("dept",    "개발팀")
                        .param("title",   "도입 문의")
                        .param("content", "내용"))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false));
    }

    @Test
    @DisplayName("POST /sub04_02 - 연락처 형식 오류 시 400 Bad Request")
    void inquirySubmit_invalidTel_returnsBadRequest() throws Exception {
        mockMvc.perform(post("/sub04_02")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .param("name",    "홍길동")
                        .param("email",   "hong@example.com")
                        .param("tel",     "invalid!")
                        .param("dept",    "개발팀")
                        .param("title",   "도입 문의")
                        .param("content", "내용"))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false));
    }

    @Test
    @DisplayName("POST /sub04_02 - 서비스 저장 실패 시 success false 반환")
    void inquirySubmit_serviceFailure_returnsFailure() throws Exception {
        given(inquiryService.submit(any())).willReturn(false);

        mockMvc.perform(post("/sub04_02")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .param("name",          "홍길동")
                        .param("email",         "hong@example.com")
                        .param("tel",           "010-1234-5678")
                        .param("dept",          "개발팀")
                        .param("title",         "도입 문의")
                        .param("content",       "서비스 도입 관련 문의드립니다.")
                        .param("solutionGubun", "PG"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(false))
                .andExpect(jsonPath("$.message").exists());
    }

    @TestConfiguration
    static class MybatisTestConfig {
        @Bean
        public SqlSessionFactory sqlSessionFactory() throws Exception {
            TransactionFactory tf = new SpringManagedTransactionFactory();
            javax.sql.DataSource ds = Mockito.mock(javax.sql.DataSource.class);
            Environment env = new Environment("test", tf, ds);
            org.apache.ibatis.session.Configuration conf = new org.apache.ibatis.session.Configuration(env);
            SqlSessionFactory factory = Mockito.mock(SqlSessionFactory.class);
            Mockito.lenient().when(factory.getConfiguration()).thenReturn(conf);
            return factory;
        }
    }
}
