package thyyxxk.webserver.service.examinations;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.StringEscapeUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.dao.adicon.AdiconDao;
import thyyxxk.webserver.entity.examinations.adicon.*;
import thyyxxk.webserver.service.externalhttp.AdiconHttpSrvc;
import thyyxxk.webserver.utils.FilterUtil;
import thyyxxk.webserver.utils.StringUtil;
import thyyxxk.webserver.utils.TokenUtil;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Service
@DS("adicon")
public class AdiconService {
    private final AdiconHttpSrvc adiconHttpSrvc;
    private final AdiconDao dao;
    private final RestTemplate template;
    private static final Map<String, String> HINT_MAP = new HashMap<>();

    static {
        HINT_MAP.put("g", "↑");
        HINT_MAP.put("d", "↓");
    }

    @Autowired
    public AdiconService(AdiconHttpSrvc adiconHttpSrvc, AdiconDao dao, RestTemplate template) {
        this.adiconHttpSrvc = adiconHttpSrvc;
        this.dao = dao;
        this.template = template;
    }

    public String login(String type) throws Exception {
        String xml = type.equals("JYK") ? adiconHttpSrvc.jykLogin() : adiconHttpSrvc.blkLogin();
        Document document = DocumentHelper.parseText(xml);
        Element root = document.getRootElement();
        return root.getText();
    }

    public List<ListTableItem> getReportList(AdiconInquiry inquiry) throws Exception {
        JSONArray barcodesList = getPatientBarcodeList(inquiry);
        String key = URLEncoder.encode(inquiry.getKey(), StandardCharsets.UTF_8.name());
        String xmlString = adiconHttpSrvc.getReportList(key, inquiry.getBegin(), inquiry.getEnd());
        List<ListTableItem> result = new ArrayList<>();
        Element root = getRootElement(xmlString);
        List<Element> listtable = FilterUtil.cast(root.elements("listtable"));
        JAXBContext jaxbContext = JAXBContext.newInstance(ListTableItem.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        for (Element element : listtable) {
            StringReader reader = new StringReader(element.asXML());
            ListTableItem listTable = (ListTableItem) unmarshaller.unmarshal(reader);
            if (inquiry.getReportType().equals("全部") ||
                inquiry.getReportType().equals(listTable.getReportType())) {
                if (barcodesList.isEmpty() || barcodesList.contains(listTable.getCustomerBarcode())) {
                    result.add(listTable);
                }
            }
        }
        if (result.isEmpty() && !barcodesList.isEmpty()) {
            throw new BizException("没有找到此患者已发布的外送报告。");
        }
        return result;
    }

    public List<ReportDetail> getReportItemListByCustomerBarcode(AdiconInquiry inquiry) throws Exception {
        String key = URLEncoder.encode(inquiry.getKey(), StandardCharsets.UTF_8.name());
        String xmlString;
        if (inquiry.getBarcodeType() == BarcodeType.CUSTOMER) {
            xmlString = adiconHttpSrvc.getReportItemListByCustomerBarcode(key, inquiry.getBarcode(), inquiry.getReportType());
        } else {
            xmlString = adiconHttpSrvc.getReportItemListByAdiconBarcode(key, inquiry.getBarcode(), inquiry.getReportType());
        }
        List<ReportDetail> result = new ArrayList<>();
        Element root = getRootElement(xmlString);
        List<Element> items = FilterUtil.cast(root.elements("item"));
        JAXBContext jaxbContext = JAXBContext.newInstance(ReportDetail.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        for (Element element : items) {
            StringReader reader = new StringReader(element.asXML());
            ReportDetail reportDetail = (ReportDetail) unmarshaller.unmarshal(reader);
            result.add(reportDetail);
        }
        return result;
    }

    public String setSampleDownFlagByCustomerBarcode(AdiconInquiry inquiry) throws Exception {
        String key = URLEncoder.encode(inquiry.getKey(), StandardCharsets.UTF_8.name());
        String xmlString;
        if (inquiry.getBarcodeType() == BarcodeType.CUSTOMER) {
            xmlString = adiconHttpSrvc.setSampleDownFlagByCustomerBarcode(key, inquiry.getBarcode(), inquiry.getReportType());
        } else {
            xmlString = adiconHttpSrvc.setSampleDownFlagByAdiconBarcode(key, inquiry.getBarcode(), inquiry.getReportType());
        }
        Document document = DocumentHelper.parseText(xmlString);
        Element root = document.getRootElement();
        return root.getText();
    }

    public String getByteReport(AdiconInquiry inquiry) throws Exception {
        String key = URLEncoder.encode(inquiry.getKey(), StandardCharsets.UTF_8.name());
        String xmlString = adiconHttpSrvc.getByteReport(inquiry.getId(), key);
        Document document = DocumentHelper.parseText(xmlString);
        Element root = document.getRootElement();
        return root.getText();
    }

    private JSONArray getPatientBarcodeList(AdiconInquiry inquiry) {
        JSONArray list = new JSONArray();
        if (StringUtil.notBlank(inquiry.getPatNo())) {
            String url = "http://172.16.32.167:9206/thyy/api/intergration/jyjc/bar_code";
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add("token", TokenUtil.getInstance().getUserToken());
            HttpEntity<AdiconInquiry> entity = new HttpEntity<>(inquiry, httpHeaders);
            JSONObject obj = template.postForObject(url, entity, JSONObject.class);
            if (null == obj) {
                throw new BizException("没有找到此患者已发布的外送报告。");
            }
            if (obj.getIntValue("code") != 1) {
                throw new BizException(obj.getString("message"));
            }
            list = obj.getJSONArray("data");
            if (list.isEmpty()) {
                throw new BizException("没有找到此患者已发布的外送报告。");
            }
        }
        return list;
    }

    private Element getRootElement(String xmlString) throws DocumentException {
        String xmlWithoutDeclaration = removeXmlDeclaration(xmlString);
        String standardXml = StringEscapeUtils.unescapeXml(xmlWithoutDeclaration);
        standardXml = standardXml.replaceAll("\r\n", "");
        if (standardXml.startsWith("<string")) {
            int startIndex = standardXml.indexOf(">");
            int endIndex = standardXml.lastIndexOf("</string>");
            standardXml = standardXml.substring(startIndex + 1, endIndex);
        }
        if (!standardXml.startsWith("<")) {
            throw new BizException(standardXml);
        }
        Document document = DocumentHelper.parseText(standardXml);
        return document.getRootElement();
    }

    private static String removeXmlDeclaration(String xmlString) {
        // 去除XML声明
        return xmlString.replaceAll("<\\?xml.*?\\?>", "");
    }

    public List<ItemMatch> getUnMatchedList(List<ItemMatch> request) {
        StringBuilder inCodeStatementBuilder = new StringBuilder();
        for (ItemMatch item : request) {
            inCodeStatementBuilder.append(",'").append(item.getItemCode()).append("'");
        }
        String inCodeStatement = inCodeStatementBuilder.substring(1);
        List<String> matchedItems = dao.selectMatchedItems(inCodeStatement);
        request.removeIf(item -> matchedItems.contains(item.getItemCode()));
        if (request.isEmpty()) {
            return request;
        }
        StringBuilder inNameStatementBuilder = new StringBuilder();
        for (ItemMatch item : request) {
            inNameStatementBuilder.append(",'").append(item.getItemName()).append("'");
        }
        String inNameStatement = inNameStatementBuilder.substring(1);
        List<ItemMatch> autoMatchableItems = dao.selectAutoMatchableItems(inNameStatement);
        if (!autoMatchableItems.isEmpty()) {
            Map<String, String> autoMatchableMap = new HashMap<>();
            for (ItemMatch item : autoMatchableItems) {
                autoMatchableMap.put(item.getMatchName(), item.getMatchCode());
            }
            for (ItemMatch item : request) {
                if (autoMatchableMap.containsKey(item.getItemName())) {
                    item.setMatchName(item.getItemName());
                    item.setMatchCode(autoMatchableMap.get(item.getItemName()));
                }
            }
            executeMatch(request);
            request.removeIf(item -> StringUtil.notBlank(item.getMatchCode()));
        }
        return request;
    }

    public List<ItemMatch> getZdItems() {
        return dao.selectZdItems();
    }

    public List<ItemMatch> executeMatch(List<ItemMatch> request) {
        List<ItemMatch> validList = new ArrayList<>();
        for (ItemMatch item : request) {
            if (StringUtil.notBlank(item.getMatchCode())) {
                validList.add(item);
            }
        }
        if (!validList.isEmpty()) {
            dao.insertMatchItem(validList);
        }
        request.removeIf(item -> StringUtil.notBlank(item.getMatchCode()));
        return request;
    }

    public String saveToTjResult(List<ReportDetail> request) {
        if (request.isEmpty()) {
            throw new BizException("报告内容为空！");
        }

        StringBuilder inCodeStatementBuilder = new StringBuilder();
        for (ReportDetail item : request) {
            inCodeStatementBuilder.append(",'").append(item.getItemCode()).append("'");
        }
        String inCodeStatement = inCodeStatementBuilder.substring(1);
        List<ItemMatch> matchedItems = dao.selectMatchedItems2(inCodeStatement);
        if (matchedItems.isEmpty()) {
            throw new BizException("有未匹配的检验项目，请刷新页面后重试。");
        }

        StringBuilder matchCodeBuilder = new StringBuilder();
        Map<String, String> map = new HashMap<>();
        for (ItemMatch item : matchedItems) {
            map.put(item.getItemCode(), item.getMatchCode());
            matchCodeBuilder.append(",'").append(item.getMatchCode()).append("'");
        }

        for (ReportDetail item : request) {
            if (null == map.get(item.getItemCode())) {
                throw new BizException("有未匹配的检验项目，请刷新页面后重试。");
            }
            item.setItemCode(map.get(item.getItemCode()));
            item.setStr3(UUID.randomUUID().toString());
            if (StringUtil.notBlank(item.getResultReference())
                    && item.getResultReference().contains("-")) {
                String[] arr = item.getResultReference().split("-");
                item.setStr4(arr[0]);
                item.setStr5(arr[1]);
            } else {
                item.setStr4(null);
                item.setStr5(null);
            }
            if (StringUtil.isBlank(item.getResultHint())) {
                item.setStr2(null);
            } else {
                item.setStr2(HINT_MAP.get(item.getResultHint()));
            }
        }

        String matchCodeStatement = matchCodeBuilder.substring(1);
        List<String> existCheckItems = dao.selectExistCheckItem(request.get(0).getPatientNumber(), matchCodeStatement);
        request.removeIf(item -> existCheckItems.contains(item.getItemCode()));
        if (!request.isEmpty()) {
            dao.insertNewResult(request);
        }
        return "操作成功。";
    }
}



