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.stereotype.Component;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;

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(props, RestClient.builder());
    }

    /**
     * 전송 계층(transport)을 직접 지정할 수 있는 생성자. 운영 코드에서는 사용하지 않으며,
     * 테스트 등 별도의 {@link RestClient.Builder} 설정이 필요한 호출자를 위한 확장 지점이다.
     */
    MattermostRestClient(MattermostProperties props, RestClient.Builder builder) {
        this.teamId = props.teamId();
        this.rest = builder
                .baseUrl(props.baseUrl())
                .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 {
    }
}
