/*
 * Copyright 2025 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.cloud.ai.studio.admin.builder.controller;

import com.alibaba.cloud.ai.studio.runtime.domain.knowledgebase.CreateDocumentRequest;
import com.alibaba.cloud.ai.studio.runtime.domain.knowledgebase.DeleteDocumentRequest;
import com.alibaba.cloud.ai.studio.runtime.domain.knowledgebase.Document;
import com.alibaba.cloud.ai.studio.runtime.domain.knowledgebase.DocumentQuery;
import com.alibaba.cloud.ai.studio.runtime.domain.knowledgebase.IndexDocumentRequest;
import com.alibaba.cloud.ai.studio.runtime.exception.BizException;
import com.alibaba.cloud.ai.studio.runtime.enums.ErrorCode;
import com.alibaba.cloud.ai.studio.runtime.domain.PagingList;
import com.alibaba.cloud.ai.studio.runtime.domain.RequestContext;
import com.alibaba.cloud.ai.studio.runtime.domain.Result;
import com.alibaba.cloud.ai.studio.core.context.RequestContextHolder;
import com.alibaba.cloud.ai.studio.core.rag.DocumentService;
import com.alibaba.cloud.ai.studio.admin.builder.annotation.ApiModelAttribute;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;

/**
 * REST controller for managing documents in knowledge bases. Provides CRUD operations and
 * document management functionality.
 *
 * @since 1.0.0.3
 */
@RestController
@Tag(name = "rag_document")
@RequestMapping("/console/v1/knowledge-bases")
public class DocumentController {

	/** Service for handling document operations */
	private final DocumentService documentService;

	public DocumentController(DocumentService documentService) {
		this.documentService = documentService;
	}

	/**
	 * Creates new documents in the knowledge base
	 * @param kbId Knowledge base ID
	 * @param request Document creation request
	 * @return Created document IDs
	 */
	@PostMapping(value = "/{kbId}/documents")
	public Result<List<String>> createDocuments(@PathVariable("kbId") String kbId,
			@RequestBody CreateDocumentRequest request) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (Objects.isNull(kbId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("kbId"));
		}

		if (Objects.isNull(request.getType())) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("type"));
		}

		if (CollectionUtils.isEmpty(request.getFiles())) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("files"));
		}

		request.setKbId(kbId);
		List<String> docIds = documentService.createDocuments(request);
		return Result.success(context.getRequestId(), docIds);
	}

	/**
	 * Updates an existing document
	 * @param kbId Knowledge base ID
	 * @param docId Document ID
	 * @param document Document to update
	 * @return result status
	 */
	@PutMapping("/{kbId}/documents/{docId}")
	public Result<Void> updateDocument(@PathVariable("kbId") String kbId, @PathVariable("docId") String docId,
			@RequestBody Document document) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (StringUtils.isBlank(docId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("docId"));
		}

		document.setDocId(docId);
		documentService.updateDocument(document);
		return Result.success(context.getRequestId(), null);
	}

	/**
	 * Deletes a single document
	 * @param kbId Knowledge base ID
	 * @param docId Document ID
	 * @return result status
	 */
	@DeleteMapping("/{kbId}/documents/{docId}")
	public Result<Void> deleteDocument(@PathVariable("kbId") String kbId, @PathVariable("docId") String docId) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (Objects.isNull(kbId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("kbId"));
		}

		if (Objects.isNull(docId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("docId"));
		}

		documentService.deleteDocuments(DeleteDocumentRequest.builder().kbId(kbId).docIds(List.of(docId)).build());
		return Result.success(context.getRequestId(), null);
	}

	/**
	 * Deletes multiple documents in batch
	 * @param kbId Knowledge base ID
	 * @param request Document deletion request
	 * @return result status
	 */
	@DeleteMapping("/{kbId}/documents/batch-delete")
	public Result<Void> batchDeleteDocuments(@PathVariable("kbId") String kbId,
			@RequestBody DeleteDocumentRequest request) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (Objects.isNull(kbId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("kbId"));
		}

		request.setKbId(kbId);
		documentService.deleteDocuments(request);
		return Result.success(context.getRequestId(), null);
	}

	/**
	 * Retrieves a single document by ID
	 * @param kbId Knowledge base ID
	 * @param docId Document ID
	 * @return document info
	 */
	@GetMapping("/{kbId}/documents/{docId}")
	public Result<Document> getDocument(@PathVariable("kbId") String kbId, @PathVariable("docId") String docId) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (Objects.isNull(docId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("docId"));
		}

		Document document = documentService.getDocument(docId);
		return Result.success(context.getRequestId(), document);
	}

	/**
	 * Lists documents with pagination
	 * @param kbId Knowledge base ID
	 * @param query Query parameters
	 * @return Paginated list of documents
	 */
	@GetMapping("/{kbId}/documents")
	public Result<PagingList<Document>> listDocuments(@PathVariable("kbId") String kbId,
			@ApiModelAttribute DocumentQuery query) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (Objects.isNull(query)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("query"));
		}

		PagingList<Document> documents = documentService.listDocuments(kbId, query);
		return Result.success(context.getRequestId(), documents);
	}

	/**
	 * Re-indexes a document with process and chunking configuration
	 * @param kbId Knowledge base ID
	 * @param docId Document ID
	 * @return result status
	 */
	@PutMapping("/{kbId}/documents/{docId}/re-index")
	public Result<Void> reIndexDocument(@PathVariable("kbId") String kbId, @PathVariable("docId") String docId,
			@RequestBody IndexDocumentRequest request) {
		RequestContext context = RequestContextHolder.getRequestContext();

		if (StringUtils.isBlank(kbId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("kbId"));
		}

		if (StringUtils.isBlank(docId)) {
			throw new BizException(ErrorCode.MISSING_PARAMS.toError("docId"));
		}

		request.setKbId(kbId);
		request.setDocId(docId);
		documentService.reIndexDocument(request);

		return Result.success(context.getRequestId(), null);
	}

}
