package com.devjob.controller;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.devjob.domain.Company;
import com.devjob.dto.JobCreateRequest;
import com.devjob.dto.JobUpdateRequest;
import com.devjob.repository.CompanyRepository;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import tools.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;

/**
 * EP18: 채용 공고 CRUD API 통합 테스트.
 */
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
class JobControllerTest {

    @Autowired
    private MockMvc mockMvc;


    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private CompanyRepository companyRepository;


    private Long companyId;
    private RequestPostProcessor owner;

    @BeforeEach
    void setUp() {
        Company company = Company.builder()
                .name("데브잡")
                .location("서울")
                .build();
        companyId = companyRepository.save(company).getId();
        this.owner = user("owner").roles("USER");   // CustomUserDetails 도입 전 단계 — 일반 인증 사용자
    }

    @Test
    @DisplayName("채용 공고 등록 → 201 Created + Location 헤더")
    void createJob() throws Exception {
        JobCreateRequest req = new JobCreateRequest("백엔드 개발자", companyId, 5000, "Spring Boot 백엔드 개발자 모집");

        mockMvc.perform(post("/api/jobs").with(owner)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(req)))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.title").value("백엔드 개발자"))
                .andExpect(jsonPath("$.data.companyName").value("데브잡"))
                .andDo(print());
    }

    @Test
    @DisplayName("존재하지 않는 채용 공고 조회 → 404 Not Found")
    void getOneNotFound() throws Exception {
        mockMvc.perform(get("/api/jobs/99999"))
                .andExpect(status().isNotFound());
    }

    @Test
    @DisplayName("채용 공고 등록 → 수정 → 삭제 흐름")
    void updateAndDeleteJob() throws Exception {
        JobCreateRequest createReq = new JobCreateRequest("프론트엔드 개발자", companyId, 4500, "React 개발자 모집");

        String response = mockMvc.perform(post("/api/jobs").with(owner)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(createReq)))
                .andExpect(status().isCreated())
                .andReturn().getResponse().getContentAsString();

        Long jobId = objectMapper.readTree(response).get("data").get("id").asLong();

        JobUpdateRequest updateReq = new JobUpdateRequest("프론트엔드 개발자(시니어)", "React/TypeScript 시니어 개발자 모집", 6000);

        mockMvc.perform(put("/api/jobs/" + jobId).with(owner)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(updateReq)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.title").value("프론트엔드 개발자(시니어)"))
                .andExpect(jsonPath("$.data.salary").value(6000));

        mockMvc.perform(delete("/api/jobs/" + jobId).with(owner))
                .andExpect(status().isNoContent());

        mockMvc.perform(get("/api/jobs/" + jobId))
                .andExpect(status().isNotFound());
    }

    @Test
    @DisplayName("채용 공고 검색 → keyword로 제목/회사명 통합 검색")
    void searchJobs() throws Exception {
        JobCreateRequest req = new JobCreateRequest("백엔드 신입 개발자", companyId, 4000, "Java/Spring 신입 채용");
        mockMvc.perform(post("/api/jobs").with(owner)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(req)))
                .andExpect(status().isCreated());

        mockMvc.perform(get("/api/jobs/search").param("keyword", "백엔드"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.content[0].title").value("백엔드 신입 개발자"));
    }
}
