package org.springblade.plugin.workflow.chat.service.impl;

import io.github.imfangs.dify.client.DifyClient;
import io.github.imfangs.dify.client.DifyClientFactory;
import io.github.imfangs.dify.client.callback.ChatflowStreamCallback;
import io.github.imfangs.dify.client.callback.CompletionStreamCallback;
import io.github.imfangs.dify.client.callback.WorkflowStreamCallback;
import io.github.imfangs.dify.client.enums.ResponseMode;
import io.github.imfangs.dify.client.event.*;
import io.github.imfangs.dify.client.model.DifyConfig;
import io.github.imfangs.dify.client.model.chat.*;
import io.github.imfangs.dify.client.model.completion.CompletionRequest;
import io.github.imfangs.dify.client.model.file.FileUploadResponse;
import io.github.imfangs.dify.client.model.workflow.WorkflowRunRequest;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.plugin.workflow.chat.core.cache.WfChatCache;
import org.springblade.plugin.workflow.chat.pojo.entity.WfChatAppEntity;
import org.springblade.plugin.workflow.chat.pojo.vo.WfChatMessageVO;
import org.springblade.plugin.workflow.chat.service.IWfChatService;
import org.springblade.plugin.workflow.core.utils.WfTaskUtil;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.File;
import java.util.Arrays;

@Service
@Log4j2
public class WfChatServiceImpl implements IWfChatService {

	@Override
	@SneakyThrows
	public SseEmitter chatMessage(WfChatMessageVO chatMessage) {
		SseEmitter emitter = new SseEmitter(30_000L);
		DifyClient chatClient = getDifyClient(chatMessage.getAppId());
		if (chatClient == null) {
			emitter.send(SseEmitter.event().data(R.fail("参数错误")));
			emitter.complete();
			return emitter;
		}

		WfChatAppEntity chatApps = WfChatCache.getChatApp(chatMessage.getAppId());

		try {
			String type = chatApps.getType();
			if (Arrays.asList("chat", "agent", "chatflow").contains(type)) { // 对话型应用
				handleChatMessage(emitter, chatMessage, chatClient);
			} else if ("workflow".equals(type)) { // 工作流应用
				handleWorkflowMessage(emitter, chatMessage, chatClient);
			} else if ("completion".equals(type)) { // 文本生成应用
				handleCompletionMessage(emitter, chatMessage, chatClient);
			} else {
				emitter.complete();
			}
		} catch (Exception e) {
			emitter.completeWithError(e);
		}

		emitter.onError(emitter::completeWithError);
		emitter.onTimeout(emitter::complete);

		return emitter;
	}

	@Override
	@SneakyThrows
	public void stopMessage(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return;
		}
		difyClient.stopChatMessage(chatMessage.getTaskId(), WfTaskUtil.getTaskUser());
	}

	@Override
	@SneakyThrows
	public R<MessageListResponse> messages(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return R.fail("参数错误");
		}
		return R.data(difyClient.getMessages(chatMessage.getConversationId(), WfTaskUtil.getTaskUser(), null, 100));
	}

	@Override
	@SneakyThrows
	public R<SuggestedQuestionsResponse> messageSuggested(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return R.fail("参数错误");
		}
		try {
			SuggestedQuestionsResponse suggestedQuestions = difyClient.getSuggestedQuestions(chatMessage.getMessageId(), WfTaskUtil.getTaskUser());
			return R.data(suggestedQuestions);
		} catch (Exception e) {
			return R.data(new SuggestedQuestionsResponse());
		}
	}

	@SneakyThrows
	@Override
	public R<ConversationListResponse> conversations(Long appsId, String lastId) {
		DifyClient difyClient = getDifyClient(appsId);
		if (difyClient == null) {
			return R.fail("参数错误");
		}
		return R.data(difyClient.getConversations(WfTaskUtil.getTaskUser(), lastId, 20, "-updated_at"));
	}

	@Override
	@SneakyThrows
	public R<Conversation> renameConversation(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return R.fail("参数错误");
		}
		return R.data(difyClient.renameConversation(chatMessage.getConversationId(), chatMessage.getConversationName(), chatMessage.getAutoGenerateName(), WfTaskUtil.getTaskUser()));
	}

	@Override
	@SneakyThrows
	public void deleteConversation(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return;
		}
		difyClient.deleteConversation(chatMessage.getConversationId(), WfTaskUtil.getTaskUser());
	}

	@Override
	@SneakyThrows
	public R<FileUploadResponse> upload(Long appId, MultipartFile multipartFile) {
		DifyClient difyClient = getDifyClient(appId);
		if (difyClient == null) {
			return R.fail("参数错误");
		}

		File file = File.createTempFile("upload_", "_" + multipartFile.getOriginalFilename());
		multipartFile.transferTo(file);
		FileUploadResponse fileUploadResponse = difyClient.uploadFile(file, WfTaskUtil.getTaskUser());
		boolean delete = file.delete();
		log.info("============Chat删除临时文件============" + delete);
		return R.data(fileUploadResponse);
	}

	@Override
	@SneakyThrows
	public R<AppParametersResponse> parameters(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return R.fail("参数错误");
		}
		return R.data(difyClient.getAppParameters());
	}

	@Override
	@SneakyThrows
	public R<AppInfoResponse> info(WfChatMessageVO chatMessage) {
		DifyClient difyClient = getDifyClient(chatMessage.getAppId());
		if (difyClient == null) {
			return R.fail("参数错误");
		}
		return R.data(difyClient.getAppInfo());
	}

	@Override
	public DifyClient getDifyClient(Long appId) {
		if (ObjectUtil.isEmpty(appId)) {
			return null;
		}
		WfChatAppEntity chatApps = WfChatCache.getChatApp(appId);
		if (chatApps == null) {
			return null;
		}
		Environment environment = SpringUtil.getContext().getEnvironment();
		boolean isDev = environment.matchesProfiles("dev");
		DifyConfig config = DifyConfig.builder()
			.baseUrl(isDev ? chatApps.getApiUrl() : StringUtil.isBlank(chatApps.getApiUrlProd()) ? chatApps.getApiUrl() : chatApps.getApiUrlProd())
			.apiKey(isDev ? chatApps.getApiKey() : StringUtil.isBlank(chatApps.getApiKeyProd()) ? chatApps.getApiKey() : chatApps.getApiKeyProd())
			.connectTimeout(5000)
			.readTimeout(60000)
			.writeTimeout(30000)
			.build();
		return DifyClientFactory.createClient(config);
	}

	/**
	 * 处理对话消息
	 */
	private void handleChatMessage(SseEmitter emitter, WfChatMessageVO chatMessage, DifyClient difyClient) throws Exception {
		ChatMessage message = ChatMessage.builder()
			.query(chatMessage.getQuery())
			.user(WfTaskUtil.getTaskUser())
			.inputs(chatMessage.getInputs())
			.conversationId(chatMessage.getConversationId())
			.files(chatMessage.getFiles())
			.responseMode(ResponseMode.STREAMING)
			.build();

		difyClient.sendChatMessageStream(message, new ChatflowStreamCallback() {
			@Override
			@SneakyThrows
			public void onMessage(MessageEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onAgentMessage(AgentMessageEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onAgentThought(AgentThoughtEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onMessageEnd(MessageEndEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
				emitter.complete();
			}

			@Override
			@SneakyThrows
			public void onWorkflowStarted(WorkflowStartedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onNodeStarted(NodeStartedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onNodeFinished(NodeFinishedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onWorkflowFinished(WorkflowFinishedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onError(ErrorEvent event) {
				emitter.send(SseEmitter.event().data(R.fail(event.getMessage())));
				emitter.complete();
			}

			@Override
			@SneakyThrows
			public void onException(Throwable throwable) {
				emitter.send(SseEmitter.event().data(R.fail(throwable.getMessage())));
				emitter.complete();
			}
		});
	}

	private void handleCompletionMessage(SseEmitter emitter, WfChatMessageVO chatMessage, DifyClient difyClient) throws Exception {
		CompletionRequest message = CompletionRequest.builder()
			.user(WfTaskUtil.getTaskUser())
			.inputs(chatMessage.getInputs())
			.files(chatMessage.getFiles())
			.responseMode(ResponseMode.STREAMING)
			.build();

		difyClient.sendCompletionMessageStream(message, new CompletionStreamCallback() {
			@Override
			@SneakyThrows
			public void onMessage(MessageEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onMessageEnd(MessageEndEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
				emitter.complete();
			}

			@Override
			@SneakyThrows
			public void onError(ErrorEvent event) {
				emitter.send(SseEmitter.event().data(R.fail(event.getMessage())));
				emitter.complete();
			}

			@Override
			@SneakyThrows
			public void onException(Throwable throwable) {
				emitter.send(SseEmitter.event().data(R.fail(throwable.getMessage())));
				emitter.complete();
			}
		});
	}

	/**
	 * 处理workflow消息
	 */
	private void handleWorkflowMessage(SseEmitter emitter, WfChatMessageVO chatMessage, DifyClient difyClient) throws Exception {
		WorkflowRunRequest request = WorkflowRunRequest.builder()
			.inputs(chatMessage.getInputs())
			.user(WfTaskUtil.getTaskUser())
			.responseMode(ResponseMode.STREAMING)
			.build();

		difyClient.runWorkflowStream(request, new WorkflowStreamCallback() {
			@Override
			@SneakyThrows
			public void onWorkflowTextChunk(WorkflowTextChunkEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onWorkflowStarted(WorkflowStartedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onNodeStarted(NodeStartedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onNodeFinished(NodeFinishedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
			}

			@Override
			@SneakyThrows
			public void onWorkflowFinished(WorkflowFinishedEvent event) {
				emitter.send(SseEmitter.event().data(R.data(event)));
				emitter.complete();
			}

			@Override
			@SneakyThrows
			public void onError(ErrorEvent event) {
				emitter.send(SseEmitter.event().data(R.fail(event.getMessage())));
				emitter.complete();
			}

			@Override
			@SneakyThrows
			public void onException(Throwable throwable) {
				emitter.send(SseEmitter.event().data(R.fail(throwable.getMessage())));
				emitter.complete();
			}
		});
	}
}
