package com.yaoai.api.controller;

import com.yaoai.api.dto.asset.AssetDTO;
import com.yaoai.api.dto.script.ScriptImportResultDTO;
import com.yaoai.api.service.AssetService;
import com.yaoai.api.service.ScriptImportService;
import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.common.response.ApiResponse;
import com.yaoai.domain.entity.ProjectAsset;
import com.yaoai.domain.mapper.ProjectAssetMapper;
import com.yaoai.security.context.TenantContext;
import com.yaoai.storage.service.TosService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

@Slf4j
@Tag(name = "项目素材")
@RestController
@RequestMapping("/projects/{projectId}/assets")
@RequiredArgsConstructor
public class AssetController {

    private final AssetService assetService;
    private final ScriptImportService scriptImportService;
    private final ProjectAssetMapper assetMapper;
    private final TosService tosService;

    @Operation(summary = "上传素材文件")
    @PostMapping(consumes = "multipart/form-data")
    public ApiResponse<AssetDTO> upload(
            @PathVariable Long projectId,
            @RequestPart("file") MultipartFile file,
            @RequestParam(value = "assetType", defaultValue = "other") String assetType) {
        return ApiResponse.success(assetService.upload(projectId, file, assetType));
    }

    @Operation(summary = "获取项目素材列表")
    @GetMapping
    public ApiResponse<List<AssetDTO>> list(@PathVariable Long projectId) {
        return ApiResponse.success(assetService.listByProject(projectId));
    }

    @Operation(summary = "删除素材")
    @DeleteMapping("/{assetId}")
    public ApiResponse<Void> delete(@PathVariable Long projectId,
                                    @PathVariable Long assetId) {
        assetService.delete(projectId, assetId);
        return ApiResponse.success();
    }

    @Operation(summary = "读取剧本文本内容（服务端代理，避免前端跨域）")
    @GetMapping("/script/content")
    public ApiResponse<Map<String, String>> readScriptContent(@PathVariable Long projectId) {
        Long tenantId = TenantContext.get();
        ProjectAsset scriptAsset = assetMapper.findByProject(projectId).stream()
                .filter(a -> tenantId.equals(a.getTenantId()) && "script".equals(a.getAssetType()))
                .findFirst()
                .orElseThrow(() -> new BizException(ErrorCode.NOT_FOUND, "未找到上传的剧本文件"));

        String content = extractText(scriptAsset.getTosKey(), scriptAsset.getMimeType(), scriptAsset.getOriginalName());
        // 限制最多 50000 字符，防止超出 LLM 上下文
        if (content.length() > 50000) {
            content = content.substring(0, 50000);
        }
        return ApiResponse.success(Map.of("content", content));
    }

    @Operation(summary = "解析剧本文档结构（预览，不写库）")
    @GetMapping("/script/parse")
    public ApiResponse<ScriptImportResultDTO> parseScript(@PathVariable Long projectId) {
        Long tenantId = TenantContext.get();
        return ApiResponse.success(scriptImportService.parseScript(projectId, tenantId));
    }

    @Operation(summary = "一键导入剧本（解析并写库：大纲+分集+角色+场景+分镜）")
    @PostMapping("/script/import")
    public ApiResponse<ScriptImportResultDTO> importScript(@PathVariable Long projectId) {
        Long tenantId = TenantContext.get();
        return ApiResponse.success(scriptImportService.importScript(projectId, tenantId));
    }

    /**
     * 根据文件类型提取纯文本：
     *  - .docx → Apache POI XWPFDocument
     *  - .doc  → Apache POI HWPFDocument
     *  - 其他  → 直接按 UTF-8 读取
     */
    private String extractText(String tosKey, String mimeType, String originalName) {
        String nameLower = originalName != null ? originalName.toLowerCase() : "";
        boolean isDocx = nameLower.endsWith(".docx")
                || "application/vnd.openxmlformats-officedocument.wordprocessingml.document".equals(mimeType);
        boolean isDoc = !isDocx && (nameLower.endsWith(".doc")
                || "application/msword".equals(mimeType));

        if (isDocx) {
            try (InputStream in = tosService.getInputStream(tosKey);
                 XWPFDocument doc = new XWPFDocument(in);
                 XWPFWordExtractor extractor = new XWPFWordExtractor(doc)) {
                return extractor.getText();
            } catch (IOException e) {
                log.error("Failed to parse .docx: key={}", tosKey, e);
                throw new BizException(ErrorCode.INTERNAL_ERROR, "解析 .docx 文件失败: " + e.getMessage());
            }
        } else if (isDoc) {
            try (InputStream in = tosService.getInputStream(tosKey);
                 HWPFDocument doc = new HWPFDocument(in);
                 WordExtractor extractor = new WordExtractor(doc)) {
                return extractor.getText();
            } catch (IOException e) {
                log.error("Failed to parse .doc: key={}", tosKey, e);
                throw new BizException(ErrorCode.INTERNAL_ERROR, "解析 .doc 文件失败: " + e.getMessage());
            }
        } else {
            // 纯文本（.txt 等）
            return tosService.readText(tosKey);
        }
    }
}
