package com.kospo.talk.controller;

import com.kospo.talk.config.exception.CustomErrorResponse;
import com.kospo.talk.config.utils.CommonUtils;
import com.kospo.talk.model.*;
import com.kospo.talk.payload.HappyDto;
import com.kospo.talk.payload.MessageDto;
import com.kospo.talk.payload.ReqDto;
import com.kospo.talk.payload.SatisDto;
import com.kospo.talk.service.TalkMemberService;
import com.kospo.talk.service.TalkMessageService;
import com.kospo.talk.service.TalkService;
import com.kospo.talk.service.WorkService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;

import java.security.Principal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@RestController
@Tag(name = "ITSM API", description = "ICT 요청 관리")
@RequestMapping("/api/ict")
@RequiredArgsConstructor
@Slf4j
public class ItsmController {

    @Value("${rabbitmq.user.exchange}")
    private String userExchange;
    @Value("${rabbitmq.user.route}")
    private String userRoute;
    @Value("${rabbitmq.talk.exchange}")
    private String talkExchange;
    @Value("${rabbitmq.talk.route}")
    private String talkRoute;
    private final WebClient itsmWebClient;
    private final TalkService talkService;
    private final WorkService workService;
    private final TalkMessageService talkMessageService;
    private final TalkMemberService talkMemberService;
    private final RabbitTemplate userTemplate;
    private final RabbitTemplate talkTemplate;

    @Operation(summary = "외부 ITSM 요청 하기", description = "itsm 요청 정보 저장 결과값으로 req_id 리턴")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                            {String.class}))),
            @ApiResponse(description = "Not found", responseCode = "404",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "text/plain", schema = @Schema(oneOf =
                            {String.class}))),
            @ApiResponse(description = "Internal Error", responseCode = "500",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                            {CustomErrorResponse.class })))
    })
    @PostMapping("/save")
    public ResponseEntity save(
            @RequestBody ReqDto reqDto,
            HttpServletRequest request,
            Principal principal
    ) {

        reqDto.setProc_sabun(principal.getName());
        reqDto.setReq_dt(CommonUtils.dateFormat("yyyyMMddHHmmss"));
        MultiValueMap cookieMap = new LinkedMultiValueMap();

        Arrays.stream(request.getCookies()).forEach((cookie) -> {
            cookieMap.add(cookie.getName(), cookie.getValue());
        });

        MultiValueMap headerMap = new LinkedMultiValueMap();

        headerMap.add("X-Forwarded-For", request.getHeader("X-Forwarded-For"));
        log.debug("itsm Save satart");
        System.out.println("itsm Save satart");
        log.debug(reqDto.getTalk_id());
        System.out.println(reqDto.getTalk_id());
        log.debug(reqDto.toString());
        System.out.println(reqDto.toString());
        try {
            Map<String, String> resultMap = itsmWebClient.post()
                    .uri("/api/saveTalk")
                    .headers(h -> h.addAll(headerMap))
                    .cookies(c -> c.addAll(cookieMap))
                    .bodyValue(reqDto)
                    .retrieve().bodyToMono(Map.class).block();
            String req_id = resultMap.get("req_id");
            log.debug("itsm Save end req_id : " + req_id);
            System.out.println("itsm Save end req_id : " + req_id);
            Talk talk = talkService.findByOne(reqDto.getTalk_id());
            talk.setReqId(req_id);
            talkService.createTalk(talk);

            MessageDto messageDto = MessageDto.builder().type("EXTERNAL_SAVE")
                            .reqId(req_id)
                                    .talkId(talk.getTalkId()).build();
            talkTemplate.convertAndSend(talkExchange, talkRoute + talk.getTalkId(), messageDto);

            return ResponseEntity.ok(req_id);
        } catch(Exception e) {
            log.debug("itsm Save error : " + e);
            System.out.println("itsm Save error : " + e);
            return ResponseEntity.ok("");
        }
    }

    @Operation(summary = "외부 ITSM 만족도 조사", description = "itsm 만족도 조사 등록")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                            {String.class}))),
            @ApiResponse(description = "Not found", responseCode = "404",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "text/plain", schema = @Schema(oneOf =
                            {String.class}))),
            @ApiResponse(description = "Internal Error", responseCode = "500",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                            {CustomErrorResponse.class })))
    })
    @PostMapping("/satis")
    public ResponseEntity satisSave(
            @RequestBody SatisDto satisDto,
            HttpServletRequest request,
            Principal principal
    ) {
        MultiValueMap cookieMap = new LinkedMultiValueMap();

        Arrays.stream(request.getCookies()).forEach((cookie) -> {
            cookieMap.add(cookie.getName(), cookie.getValue());
        });

        MultiValueMap headerMap = new LinkedMultiValueMap();

        Talk currentTalk = talkService.findByOne(satisDto.getTalk_id());

        Map<String, String> resultMap = new HashMap<>();
        headerMap.add("X-Forwarded-For", request.getHeader("X-Forwarded-For"));
        resultMap = itsmWebClient.post()
                .uri("/api/savePoint")
                .headers(h -> h.addAll(headerMap))
                .cookies(c -> c.addAll(cookieMap))
                .bodyValue(HappyDto.builder()
                        .req_id(currentTalk.getReqId())
                        .h_point(satisDto.getH_point())
                        .opinion(satisDto.getOpinion()).build()
                )
                .retrieve().bodyToMono(Map.class).block();

        String result = resultMap.get("result");
        if(result.equals("s")) {
            talkService.ratingUpdate(currentTalk.getReqId());
            Work work = workService.findByTalkId(currentTalk.getTalkId());
            MessageDto messageDto = MessageDto.builder()
                    .type("STATUS")
                    .message("만족도 조사에 참여해 주셔서 감사해요.\n앞으로도 많은 참여 부탁드려요.")
                    .talkId(currentTalk.getTalkId())
                    .workId(work.getWorkId())
                    .workNm(work.getWorkNm())
                    .insSabun("info")
                    .insName("시스템")
                    .insDate(LocalDateTime.now())
                    .build();
            talkMessageService.save(TalkMessage.builder()
                    .id(TalkMessageId.builder().talkId(messageDto.getTalkId()).sabun(messageDto.getInsSabun()).insDate(messageDto.getInsDate()).build())
                    .message(messageDto.getMessage())
                    .searchYn(false)
                    .insName(messageDto.getInsName()).build()
            );


            talkMemberService.findAllByTalkId(messageDto.getTalkId()).stream().forEach(talkMember -> {
                userTemplate.convertAndSend(userExchange, userRoute + talkMember.getId().getSabun(), messageDto);
            });

        }
        return ResponseEntity.ok(resultMap.get("result"));
    }
}
