package com.kospo.talk.controller;

import com.kospo.talk.config.exception.CustomErrorResponse;
import com.kospo.talk.model.ManualId;
import com.kospo.talk.payload.ManualDto;
import com.kospo.talk.payload.VManualDto;
import com.kospo.talk.service.ManualService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
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 lombok.RequiredArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourceRegion;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.security.Principal;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;

@RestController
@Tag(name = "Manual Api", description = "업무 매뉴얼 관리")
@RequestMapping("/api")
@RequiredArgsConstructor
public class ManualController {
    private final ManualService manualService;

    @Operation(summary = "매뉴얼 조회(문서)", description = "본인의 work id 로 해당 매뉴얼 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", array = @ArraySchema(
                            schema = @Schema(oneOf =
                                    {ManualDto.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 })))
    })
    @GetMapping("/manual")
    public ResponseEntity docSearch(
        @Parameter(description = "검색") @RequestParam(name="search", defaultValue = "", required = false) String search,
        @Parameter(description = "업무아이디") @RequestParam(name="workId", defaultValue = "", required = false) String workId,
        @Parameter(description = "매뉴얼 타입: 0000(문서) 0100(사진) 0200(동영상)") @RequestParam(name="type", required = false) String type,
        Principal principal
    ) {
        return ResponseEntity.ok(manualService.findDocSearch(search, workId, type));
    }


    @Operation(summary = "매뉴얼 조회(문서) 개인용", description = "본인의 사번으로 해당 매뉴얼 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", array = @ArraySchema(
                            schema = @Schema(oneOf =
                                    {ManualDto.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 })))
    })
    @GetMapping("/manual/person")
    public ResponseEntity docSearch(
        @Parameter(description = "매뉴얼 타입: 0000(문서) 0100(사진) 0200(동영상)") @RequestParam(name="type", required = true) String type,
        Principal principal
    ) {
        return ResponseEntity.ok(manualService.findDocSearchPerson(principal.getName(), type));
    }

    @Operation(summary = "매뉴얼 조회(이미지, 동영상)", description = "본인의 work id 로 해당 매뉴얼 조회")
    @ApiResponses({
        @ApiResponse(description = "Success", responseCode = "200",
                content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", array = @ArraySchema(
                        schema = @Schema(oneOf =
                                {ManualDto.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 })))
    })
    @GetMapping("/manual/intro")
    public ResponseEntity introList(
        @Parameter(description = "업무 아이디") @RequestParam(name="workId") String workId,
        Principal principal
    ) {
        return ResponseEntity.ok(manualService.introList(workId));
    }

    @Operation(summary = "매뉴얼 조회(문서)", description = "본인의 work id 로 문서 매뉴얼 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", array = @ArraySchema(
                            schema = @Schema(oneOf =
                                    {ManualDto.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 })))
    })
    @GetMapping("/manual/doc")
    public ResponseEntity docList(
        @Parameter(description = "업무 아이디") @RequestParam(name="workId") String workId,
        Principal principal
    ) {
        return ResponseEntity.ok(manualService.findDoc(workId));
    }

    @Operation(summary = "매뉴얼 조회(동영상)", description = "본인의 work id 로 동영상 매뉴얼 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", array = @ArraySchema(
                            schema = @Schema(oneOf =
                                    {ManualDto.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 })))
    })
    @GetMapping("/manual/video")
    public ResponseEntity videoList(
            @Parameter(description = "검색") @RequestParam(name="search", defaultValue = "", required = false) String search,
            @Parameter(description = "업무 아이디") @RequestParam(name="workId", defaultValue = "", required = false) String workId,
        Principal principal
    ) {
        return ResponseEntity.ok(manualService.findVideo(search, workId));
    }

    @Operation(summary = "매뉴얼 조회(동영상)", description = "본인이 등록한 work id 로 동영상 매뉴얼 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", array = @ArraySchema(
                            schema = @Schema(oneOf =
                                    {ManualDto.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 })))
    })
    @GetMapping("/manual/video/sm")
    public ResponseEntity videoListSm(
        @Parameter(description = "업무 아이디") @RequestParam(name="workId", required = false) String workId,
        Principal principal
    ) {
        return ResponseEntity.ok(manualService.findVideoSm(workId, principal.getName()));
    }

    @Operation(summary = "매뉴얼(이미지) 스트리밍", description = "workId, vnm 으로 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                                    {Byte[].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 })))
    })
    @GetMapping("/manual/view/image")
    public ResponseEntity<byte[]> contentImageView(
            @Parameter(description = "업무 아이디") @RequestParam("workId") String workId,
            @Parameter(description = "파일 물리명") @RequestParam("vnm") String vnm,
            Principal principal) {

        byte[] bytes = manualService.loadImage(
                ManualId.builder()
                        .workId(workId)
                        .vnm(vnm).build()
        );
        CacheControl cacheControl = CacheControl.maxAge(Duration.ofDays(7)).cachePublic().staleWhileRevalidate(Duration.ofDays(7));

        // HTTP 헤더 설정
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_PNG);
        headers.setContentLength(bytes.length);
        return ResponseEntity.ok()
                .headers(headers)
                .cacheControl(cacheControl)
                .body(bytes);
//        return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
    }

    @Operation(summary = "매뉴얼(비디오) 스트리밍", description = "workId, vnm 으로 조회")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                                    {Byte[].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 })))
    })
    @GetMapping("/manual/view/video")
    public ResponseEntity<List<ResourceRegion>> contentMovieView(
            @Parameter(description = "동영상 아이디") @RequestParam("id") int id,
            @Parameter(description = "숏츠 : S 원본 : O") @RequestParam("id") String type,
            @RequestHeader HttpHeaders headers,
            Principal principal) {

        try {
            Resource video = manualService.loadVideo(id, type);
            List<ResourceRegion> regions = HttpRange.toResourceRegions(headers.getRange(), video);
            return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
                    .contentType(MediaType.parseMediaType("video/mp4"))
                    .body(regions);

        } catch (IOException e) {
            // 클라이언트가 연결을 끊었을 때 발생하는 예외 처리
            // 로그를 남기고 스트리밍을 중단
            System.err.println("IOException occurred during streaming: " + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Operation(summary = "매뉴얼(문서) 다운로드", description = "workId, vnm 으로 다운로드")
    @ApiResponses({
            @ApiResponse(description = "Success", responseCode = "200",
                    content = @io.swagger.v3.oas.annotations.media.Content(mediaType = "application/json", schema = @Schema(oneOf =
                                    {Byte[].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 })))
    })
    @GetMapping("/manual/download/doc")
    public ResponseEntity<byte[]> docDownload(
            @Parameter(description = "업무 아이디") @RequestParam("workId") String workId,
            @Parameter(description = "파일 물리명") @RequestParam("vnm") String vnm,
            Principal principal) {

        HashMap<String, Object> map = manualService.loadOoc(
                ManualId.builder()
                        .workId(workId)
                        .vnm(vnm).build()
        );

        // HTTP 헤더 설정
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + URLEncoder.encode((String) map.get("onm")) + "\"");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentLength(((byte[])map.get("data")).length);

        return new ResponseEntity<>((byte[])map.get("data"), headers, HttpStatus.OK);
    }

    @Operation(summary = "매뉴얼 저장", description = "메뉴얼 저장 (required : workId, version, type, onm,. data) 0000 문서매뉴얼, 0100 이미지")
    @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("/manual")
    public ResponseEntity save(@RequestBody ManualDto manualDto) {
        manualService.save(manualDto);
        return ResponseEntity.ok("success");
    }

    @Operation(summary = "동영상 매뉴얼 저장", description = "동영상 메뉴얼 저장 (required : workId, sonm, onm)")
    @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("/manual/video")
    public ResponseEntity videoSave(@RequestBody VManualDto vmanualDto) {
        manualService.videoSave(vmanualDto);
        return ResponseEntity.ok("success");
    }

    @Operation(summary = "동영상 매뉴얼 삭제", description = "동영상 메뉴얼 삭제 (delete_yn = true)")
    @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 })))
    })
    @DeleteMapping("/manual/video/{id}")
    public ResponseEntity videoDelete(
            @Parameter(description = "동영상 매뉴얼 아이디") @PathVariable("id") int id,
            Principal principal
    ) {
        return ResponseEntity.ok(manualService.videoDelete(principal.getName(), id));
    }

    @Operation(summary = "매뉴얼 수정", description = "메뉴얼 수정 (required : workId, version, type, onm, data) 동영상 이미지 메뉴얼 지원 안함")
    @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 })))
    })
    @PutMapping("/manual")
    public ResponseEntity update(@RequestBody ManualDto manualDto) {
        manualService.update(manualDto);
        return ResponseEntity.ok("success");
    }

    @Operation(summary = "매뉴얼 삭제", description = "메뉴얼 삭제")
    @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 })))
    })
    @DeleteMapping("/manual/{workId}/{vnm}")
    public ResponseEntity delete(
            @Parameter(description = "업무 아이디") @PathVariable("workId") String workId,
            @Parameter(description = "물리파일명") @PathVariable("vnm") String vnm
    ) {
        manualService.delete(workId, vnm);
        return ResponseEntity.ok("success");
    }
}
