package kr.itn.itnhub.mattermost;

import com.fasterxml.jackson.databind.JsonNode;
import kr.itn.itnhub.config.MattermostProperties;
import org.springframework.http.MediaType;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;

import java.net.http.HttpClient;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

@Component
public class MattermostRestClient implements MattermostClient {

    private final RestClient rest;
    private final String teamId;

    public MattermostRestClient(MattermostProperties props) {
        this.teamId = props.teamId();
        // JDK HttpClient의 기본 HTTP/2 h2c 업그레이드 협상이 WireMock(Jetty) 상대로
        // POST 요청에서 간헐적으로 RST_STREAM을 유발해 HTTP/1.1로 고정한다.
        HttpClient httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_1_1)
                .build();
        this.rest = RestClient.builder()
                .baseUrl(props.baseUrl())
                .requestFactory(new JdkClientHttpRequestFactory(httpClient))
                .defaultHeader("Authorization", "Bearer " + props.token())
                .build();
    }

    @Override
    public Optional<String> findChannelIdByInternalName(String internalName) {
        try {
            JsonNode body = rest.get()
                    .uri("/api/v4/teams/{teamId}/channels/name/{name}", teamId, internalName)
                    .retrieve()
                    .onStatus(status -> status.value() == 404, (req, res) -> {
                        throw new NotFound();
                    })
                    .body(JsonNode.class);

            return idOf(body);
        } catch (NotFound e) {
            return Optional.empty();
        } catch (RestClientException e) {
            throw new MattermostException("채널 조회 실패: " + internalName, e);
        }
    }

    @Override
    public Optional<String> findChannelIdByDisplayName(String displayName) {
        try {
            JsonNode channels = rest.get()
                    .uri(uri -> uri.path("/api/v4/users/me/teams/{teamId}/channels")
                            .build(teamId))
                    .retrieve()
                    .body(JsonNode.class);

            if (channels == null || !channels.isArray()) {
                return Optional.empty();
            }
            for (JsonNode channel : channels) {
                if (displayName.equals(channel.path("display_name").asText())) {
                    return idOf(channel);
                }
            }
            return Optional.empty();
        } catch (RestClientException e) {
            throw new MattermostException("채널 목록 조회 실패", e);
        }
    }

    @Override
    public String createPrivateChannel(String internalName, String displayName) {
        Map<String, String> body = new LinkedHashMap<>();
        body.put("team_id", teamId);
        body.put("name", internalName);
        body.put("display_name", displayName);
        body.put("type", "P");
        body.put("purpose", "");
        body.put("header", "");

        try {
            JsonNode created = rest.post()
                    .uri("/api/v4/channels")
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(body)
                    .retrieve()
                    .body(JsonNode.class);

            return idOf(created).orElseThrow(() ->
                    new MattermostException("채널 생성 응답에 id가 없습니다: " + displayName));
        } catch (RestClientException e) {
            throw new MattermostException("채널 생성 실패: " + displayName, e);
        }
    }

    private Optional<String> idOf(JsonNode node) {
        if (node == null) {
            return Optional.empty();
        }
        String id = node.path("id").asText("");
        return id.isBlank() ? Optional.empty() : Optional.of(id);
    }

    /** 404를 정상 흐름으로 되돌리기 위한 내부 신호. 밖으로 새지 않는다. */
    private static final class NotFound extends RuntimeException {
    }
}
