package kr.itn.itnhub.review;

import kr.itn.itnhub.org.OrgNotFoundException;
import kr.itn.itnhub.org.Organization;
import kr.itn.itnhub.org.OrganizationMapper;
import kr.itn.itnhub.seed.SeedParseException;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
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.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/** 기관관리 상세의 권리확인 탭이 부르는 엔드포인트. */
@RestController
public class ReviewController {

    private final ReviewService reviewService;
    private final ReviewImportService importService;
    private final OrganizationMapper orgMapper;

    public ReviewController(ReviewService reviewService, ReviewImportService importService,
                             OrganizationMapper orgMapper) {
        this.reviewService = reviewService;
        this.importService = importService;
        this.orgMapper = orgMapper;
    }

    @PostMapping("/api/orgs/{id}/review/import")
    public ReviewImportReport upload(@PathVariable("id") Long orgId, @RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            throw new SeedParseException("업로드된 파일이 비어 있습니다.");
        }
        String filename = file.getOriginalFilename();
        if (filename == null || !hasAllowedExtension(filename)) {
            throw new SeedParseException("엑셀 파일(.xlsx 또는 .xlsm)만 업로드할 수 있습니다.");
        }
        try (InputStream in = file.getInputStream()) {
            return importService.importFile(orgId, in);
        } catch (IOException e) {
            throw new SeedParseException("엑셀 파일을 읽지 못했습니다.", e);
        }
    }

    /**
     * keyword는 사이트명/게시판명/제목 통합검색, site/board/title은 열별 조건(서로 AND)이다.
     */
    @GetMapping("/api/orgs/{id}/review")
    public ReviewPage list(@PathVariable("id") Long orgId,
                            @RequestParam(required = false) String keyword,
                            @RequestParam(required = false) String site,
                            @RequestParam(required = false) String board,
                            @RequestParam(required = false) String title,
                            @RequestParam(defaultValue = "0") int page,
                            @RequestParam(defaultValue = "30") int size) {
        return reviewService.list(orgId, keyword, site, board, title, page, size);
    }

    /** 목록에서 체크한 건들에 같은 값을 한 번에 반영한다. 반영된 건수를 돌려준다. */
    @PutMapping("/api/orgs/{id}/review/bulk")
    public java.util.Map<String, Integer> updateBulk(@PathVariable("id") Long orgId,
                                                     @RequestBody BulkJudgmentRequest request) {
        return java.util.Map.of("updated", reviewService.updateBulk(orgId, request));
    }

    /** 목록에서 체크한 건들을 지운다. */
    @PostMapping("/api/orgs/{id}/review/bulk-delete")
    public java.util.Map<String, Integer> deleteBulk(@PathVariable("id") Long orgId,
                                                     @RequestBody java.util.List<Long> ids) {
        return java.util.Map.of("deleted", reviewService.deleteBulk(orgId, ids));
    }

    @GetMapping("/api/orgs/{id}/review/{itemId}")
    public ReviewItem get(@PathVariable("id") Long orgId, @PathVariable Long itemId) {
        return reviewService.get(orgId, itemId);
    }

    @PutMapping("/api/orgs/{id}/review/{itemId}")
    public ReviewItem update(@PathVariable("id") Long orgId, @PathVariable Long itemId,
                              @RequestBody JudgmentRequest request) {
        return reviewService.updateJudgment(orgId, itemId, request);
    }

    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping("/api/orgs/{id}/review/{itemId}")
    public void delete(@PathVariable("id") Long orgId, @PathVariable Long itemId) {
        reviewService.delete(orgId, itemId);
    }

    /** 한글 파일명이라 ChannelFeedController.download와 동일하게 RFC 5987 인코딩을 쓴다. */
    @GetMapping("/api/orgs/{id}/review/download")
    public ResponseEntity<byte[]> download(@PathVariable("id") Long orgId) {
        Organization org = orgMapper.findById(orgId);
        if (org == null) {
            throw new OrgNotFoundException("기관을 찾을 수 없습니다: " + orgId);
        }
        byte[] content = reviewService.downloadWorkbook(orgId);

        String filename = "권리확인_" + org.getOrgName() + ".xlsx";
        String encodedName = URLEncoder.encode(filename, StandardCharsets.UTF_8).replace("+", "%20");

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedName)
                .contentType(MediaType.parseMediaType(
                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
                .body(content);
    }

    private static boolean hasAllowedExtension(String filename) {
        String lower = filename.toLowerCase();
        return lower.endsWith(".xlsx") || lower.endsWith(".xlsm");
    }
}
