package com.ruoyi.jarvis.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.jarvis.config.KdocsCloudConfig;
import com.ruoyi.jarvis.service.IKdocsOpenApiService;
import com.ruoyi.jarvis.util.KdocsOpenApiClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

@Service
public class KdocsOpenApiServiceImpl implements IKdocsOpenApiService {

    @Autowired
    private KdocsCloudConfig kdocsCloudConfig;

    private static String enc(String s) {
        try {
            return URLEncoder.encode(s == null ? "" : s, "UTF-8").replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            throw new AssertionError(e);
        }
    }

    private String host() {
        return kdocsCloudConfig.getApiHost().replaceAll("/$", "");
    }

    private JSONObject getOpenApi(String pathWithLeadingSlash, String accessToken) {
        String url = host() + pathWithLeadingSlash
            + (pathWithLeadingSlash.contains("?") ? "&" : "?")
            + "access_token=" + enc(accessToken);
        JSONObject root = KdocsOpenApiClient.exchange("GET", url, null, false);
        return KdocsOpenApiClient.requireBusinessData(root);
    }

    private JSONObject postOpenApi(String pathWithLeadingSlash, String accessToken, String jsonBody) {
        String url = host() + pathWithLeadingSlash
            + (pathWithLeadingSlash.contains("?") ? "&" : "?")
            + "access_token=" + enc(accessToken);
        JSONObject root = KdocsOpenApiClient.exchange("POST", url, jsonBody, false);
        return KdocsOpenApiClient.requireBusinessData(root);
    }

    @Override
    public JSONObject getUserInfoFlat(String accessToken) {
        JSONObject data = getOpenApi("/api/v1/openapi/user/basic", accessToken);
        JSONObject flat = new JSONObject();
        JSONObject id = data.getJSONObject("id");
        if (id != null) {
            flat.put("open_id", id.getString("open_id"));
            flat.put("user_id", id.getString("open_id"));
        }
        flat.put("name", data.getString("nickname"));
        flat.put("nickname", data.getString("nickname"));
        flat.put("avatar", data.getString("avatar"));
        return flat;
    }

    @Override
    public JSONObject getFileList(String accessToken, Map<String, Object> params) {
        int count = 20;
        if (params != null) {
            if (params.get("page_size") != null) {
                count = ((Number) params.get("page_size")).intValue();
            } else if (params.get("pageSize") != null) {
                count = ((Number) params.get("pageSize")).intValue();
            }
        }
        StringBuilder path = new StringBuilder("/api/v1/openapi/personal/files/flat?count=")
            .append(count)
            .append("&order=desc&order_by=mtime&ignore=group");
        if (params != null) {
            Object off = params.get("next_offset");
            if (off == null) {
                off = params.get("cursor");
            }
            if (off != null) {
                path.append("&offset=").append(off.toString());
            }
            Object nf = params.get("next_filter");
            if (nf != null && StringUtils.isNotBlank(nf.toString())) {
                path.append("&filter=").append(enc(nf.toString()));
            }
        }
        JSONObject data = getOpenApi(path.toString(), accessToken);
        JSONArray files = data.getJSONArray("files");
        JSONArray normalized = new JSONArray();
        if (files != null) {
            for (int i = 0; i < files.size(); i++) {
                JSONObject f = files.getJSONObject(i);
                JSONObject id = f.getJSONObject("id");
                String openId = id != null ? id.getString("open_id") : null;
                JSONObject row = new JSONObject();
                row.put("file_token", openId);
                row.put("file_name", f.getString("fname"));
                row.put("file_type", f.getString("ftype"));
                row.put("mtime", f.get("mtime"));
                normalized.add(row);
            }
        }
        JSONObject out = new JSONObject();
        out.put("files", normalized);
        out.put("next_offset", data.get("next_offset"));
        out.put("next_filter", data.getString("next_filter"));
        Integer no = data.getInteger("next_offset");
        out.put("has_more", no != null && no != -1);
        return out;
    }

    @Override
    public JSONObject getFileInfo(String accessToken, String fileToken) {
        String path = "/api/v1/openapi/personal/files/" + enc(fileToken) + "/simple/info";
        return getOpenApi(path, accessToken);
    }

    @Override
    public JSONObject getSheetList(String accessToken, String fileToken) {
        String path = "/api/v1/openapi/ksheet/" + enc(fileToken) + "/sheets";
        JSONObject data = getOpenApi(path, accessToken);
        JSONArray infos = data.getJSONArray("sheets_info");
        JSONArray sheets = new JSONArray();
        if (infos != null) {
            for (int i = 0; i < infos.size(); i++) {
                JSONObject si = infos.getJSONObject(i);
                JSONObject s = new JSONObject();
                s.put("name", si.getString("sheet_name"));
                s.put("sheet_idx", si.getInteger("sheet_idx"));
                s.put("sheet_id", si.get("sheet_id"));
                s.put("sheet_type", si.getString("sheet_type"));
                sheets.add(s);
            }
        }
        JSONObject out = new JSONObject();
        out.put("sheets", sheets);
        out.put("sheets_info", infos);
        return out;
    }

    @Override
    public JSONObject readCells(String accessToken, String fileToken, int sheetIdx, String range) {
        String path = "/api/v1/openapi/ksheet/" + enc(fileToken) + "/sheets/" + sheetIdx + "/cells";
        if (StringUtils.isNotBlank(range)) {
            path += "?range=" + enc(range.trim());
        }
        return getOpenApi(path, accessToken);
    }

    @Override
    public JSONObject updateCells(String accessToken, String fileToken, int sheetIdx, String range, List<List<Object>> values) {
        JSONObject body = new JSONObject();
        body.put("range", range);
        JSONArray valuesArray = new JSONArray();
        if (values != null) {
            for (List<Object> row : values) {
                JSONArray rowArray = new JSONArray();
                if (row != null) {
                    for (Object cell : row) {
                        rowArray.add(cell != null ? cell : "");
                    }
                }
                valuesArray.add(rowArray);
            }
        }
        body.put("values", valuesArray);
        String path = "/api/v1/openapi/ksheet/" + enc(fileToken) + "/sheets/" + sheetIdx + "/cells";
        return postOpenApi(path, accessToken, body.toJSONString());
    }

    @Override
    public JSONObject createSheet(String accessToken, String fileToken, String sheetName) {
        JSONObject body = new JSONObject();
        body.put("name", sheetName);
        String path = "/api/v1/openapi/ksheet/" + enc(fileToken) + "/sheets";
        return postOpenApi(path, accessToken, body.toJSONString());
    }

    @Override
    public JSONObject batchUpdateCells(String accessToken, String fileToken, int sheetIdx, List<Map<String, Object>> updates) {
        JSONObject body = new JSONObject();
        JSONArray updatesArray = new JSONArray();
        if (updates != null) {
            for (Map<String, Object> update : updates) {
                JSONObject u = new JSONObject();
                u.put("range", update.get("range"));
                @SuppressWarnings("unchecked")
                List<List<Object>> values = (List<List<Object>>) update.get("values");
                JSONArray valuesArray = new JSONArray();
                if (values != null) {
                    for (List<Object> row : values) {
                        JSONArray rowArray = new JSONArray();
                        if (row != null) {
                            for (Object cell : row) {
                                rowArray.add(cell != null ? cell : "");
                            }
                        }
                        valuesArray.add(rowArray);
                    }
                }
                u.put("values", valuesArray);
                updatesArray.add(u);
            }
        }
        body.put("updates", updatesArray);
        String path = "/api/v1/openapi/ksheet/" + enc(fileToken) + "/sheets/" + sheetIdx + "/cells/batch";
        return postOpenApi(path, accessToken, body.toJSONString());
    }
}
