package kr.itn.itnhub.feed;

import kr.itn.itnhub.mattermost.MattermostClient;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 기관관리 상세의 게시물/자료 탭이 부르는 읽기 전용 엔드포인트.
 * 브라우저는 Mattermost를 절대 직접 호출하지 않고 전부 이 컨트롤러를 거친다.
 */
@RestController
public class ChannelFeedController {

    private final ChannelFeedService feedService;
    private final MattermostClient mattermost;

    public ChannelFeedController(ChannelFeedService feedService, MattermostClient mattermost) {
        this.feedService = feedService;
        this.mattermost = mattermost;
    }

    @GetMapping("/api/orgs/{id}/posts")
    public List<PostView> posts(@PathVariable Long id, @RequestParam String channel) {
        return feedService.posts(id, channel);
    }

    @GetMapping("/api/orgs/{id}/files")
    public List<FileView> files(@PathVariable Long id, @RequestParam String channel) {
        return feedService.files(id, channel);
    }

    /**
     * 메시지를 보낸다. {@code message}와 {@code files} 둘 다 비어 있으면 400을 돌려준다.
     * {@code notice}가 참이면 정책 A(단일 활성 공지)를 적용한다 - 자세한 내용은
     * {@link ChannelFeedService#sendMessage}를 참고.
     */
    @PostMapping("/api/orgs/{id}/messages")
    public SendResult sendMessage(
            @PathVariable Long id,
            @RequestParam String channel,
            @RequestParam(required = false, defaultValue = "") String message,
            @RequestParam(required = false, defaultValue = "false") boolean notice,
            @RequestParam(required = false) List<MultipartFile> files) {

        List<MultipartFile> submitted = files == null ? List.of() : files;
        boolean anyFile = submitted.stream().anyMatch(f -> !f.isEmpty());
        if (message.isBlank() && !anyFile) {
            throw new InvalidMessageException("메시지 내용이나 첨부파일 중 하나는 있어야 합니다.");
        }

        List<UploadedFile> uploaded = new ArrayList<>();
        for (MultipartFile file : submitted) {
            if (file.isEmpty()) {
                continue;
            }
            try {
                uploaded.add(new UploadedFile(file.getOriginalFilename(), file.getBytes(), file.getContentType()));
            } catch (IOException e) {
                throw new InvalidMessageException("첨부파일을 읽지 못했습니다: " + file.getOriginalFilename());
            }
        }

        return feedService.sendMessage(id, channel, message, uploaded, notice);
    }

    /** 채널의 현재 공지(가장 최근에 고정된 게시글). 없으면 204를 돌려준다. */
    @GetMapping("/api/orgs/{id}/notice")
    public ResponseEntity<PostView> notice(@PathVariable Long id, @RequestParam String channel) {
        PostView notice = feedService.currentNotice(id, channel);
        return notice == null ? ResponseEntity.noContent().build() : ResponseEntity.ok(notice);
    }

    /** 공지 해제: 고정을 전부 풀고 헤더를 비운다. 원본 글은 채팅 기록에 남는다. */
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping("/api/orgs/{id}/notice")
    public void clearNotice(@PathVariable Long id, @RequestParam String channel) {
        feedService.clearNotice(id, channel);
    }

    /**
     * 한글 파일명이 대부분이라 {@code Content-Disposition}은 반드시 RFC 5987의
     * {@code filename*=UTF-8''...} 형식으로 인코딩해야 한다. 일반 {@code filename="..."}
     * 만 쓰면 브라우저마다 한글이 깨진다.
     */
    @GetMapping("/api/files/{fileId}")
    public ResponseEntity<byte[]> download(@PathVariable String fileId) {
        FileRef info = mattermost.fileInfo(fileId);
        byte[] content = mattermost.downloadFile(fileId);

        String encodedName = URLEncoder.encode(info.name(), StandardCharsets.UTF_8)
                .replace("+", "%20");
        MediaType contentType = resolveContentType(info.mimeType());

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedName)
                .contentType(contentType)
                .body(content);
    }

    private MediaType resolveContentType(String mimeType) {
        if (mimeType == null || mimeType.isBlank()) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
        try {
            return MediaType.parseMediaType(mimeType);
        } catch (org.springframework.util.InvalidMimeTypeException e) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
    }
}
