package com.sz.admin.monitor.utils;


import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.util.Timeout;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

public class HikHdd {

    /**
     * 仅 HTTP 版本：请求 /ISAPI/ContentMgmt/Storage/hdd，解析 XML，返回汇总信息。
     * @throws Exception 网络/认证/XML 解析失败时抛出
     */
    public static HddSummary fetchHddSummaryHttp(String ip, int port, String user, String pass) throws Exception {
        String url = "http://" + ip + ":" + port + "/ISAPI/ContentMgmt/Storage/hdd";

        HttpHost target = new HttpHost("http", ip, port);
        Credentials creds = new UsernamePasswordCredentials(user, pass.toCharArray());

        BasicCredentialsProvider provider = new BasicCredentialsProvider();
        provider.setCredentials(new AuthScope(target.getHostName(), target.getPort()), creds);

        var cm = PoolingHttpClientConnectionManagerBuilder.create().build();
        RequestConfig rc = RequestConfig.custom()
                .setConnectionRequestTimeout(Timeout.ofSeconds(10))
                .setConnectTimeout(Timeout.ofSeconds(6))
                .setResponseTimeout(Timeout.ofSeconds(10))
                .build();

        try (CloseableHttpClient client = HttpClients.custom()
                .setDefaultCredentialsProvider(provider)      // 401 后自动协商 Digest/Basic
                .setConnectionManager(cm)
                .setDefaultRequestConfig(rc)
                .build()) {

            var get = new org.apache.hc.client5.http.classic.methods.HttpGet(URI.create(url));
            try (ClassicHttpResponse resp = client.executeOpen(null, get, null)) {
                int code = resp.getCode();
                String body = EntityUtils.toString(resp.getEntity());
                if (code < 200 || code >= 300) {
                    throw new RuntimeException("HTTP " + code + " body: " + body);
                }
                return parseHddXml(body);
            }
        }
    }

    private static HddSummary parseHddXml(String xml) throws Exception {
        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
        f.setNamespaceAware(true);
        Document doc = f.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));

        XPath xp = XPathFactory.newInstance().newXPath();
        NodeList hdds = (NodeList) xp.evaluate("//*[local-name()='hdd']", doc, XPathConstants.NODESET);

        List<Disk> list = new ArrayList<>();
        long totalMb = 0, freeMb = 0;

        for (int i = 0; i < hdds.getLength(); i++) {
            var n = hdds.item(i);
            String id     = text(xp, "./*[local-name()='id']", n);
            String status = text(xp, "./*[local-name()='status']", n);
            String model  = text(xp, "./*[local-name()='hddModel']", n);

            long capMb  = parseLongSafe(text(xp, "./*[local-name()='capacity']", n));   // MB
            long free   = parseLongSafe(text(xp, "./*[local-name()='freeSpace']", n));  // MB

            totalMb += capMb;
            freeMb  += free;

            list.add(new Disk(id, status, model, capMb, free));
        }

        long usedMb = Math.max(0, totalMb - freeMb);
        return new HddSummary(list, totalMb, freeMb, usedMb);
    }

    private static String text(XPath xp, String expr, org.w3c.dom.Node ctx) throws Exception {
        String s = (String) xp.evaluate(expr, ctx, XPathConstants.STRING);
        return (s == null || s.isEmpty()) ? null : s.trim();
    }

    private static long parseLongSafe(String s) {
        if (s == null || s.isEmpty()) return 0L;
        try { return Long.parseLong(s.trim()); } catch (Exception e) { return 0L; }
    }


    public static class Disk {
        public final String id;
        public final String status;
        public final String model;
        public final long capacityMiB;
        public final long freeMiB;

        public Disk(String id, String status, String model, long capacityMiB, long freeMiB) {
            this.id = id;
            this.status = status;
            this.model = model;
            this.capacityMiB = capacityMiB;
            this.freeMiB = freeMiB;
        }

        public double capacityGiB() { return capacityMiB / 1024.0; }
        public double freeGiB()     { return freeMiB / 1024.0; }
        public double usedGiB()     { return (capacityMiB - freeMiB) / 1024.0; }
    }

    public static class HddSummary {
        public final List<Disk> disks;
        public final long totalMiB;
        public final long freeMiB;
        public final long usedMiB;

        public final int diskCount; // 总硬盘数量
        public final int okCount;   // status=ok 的数量

        public HddSummary(List<Disk> disks, long totalMiB, long freeMiB, long usedMiB) {
            this.disks = disks;
            this.totalMiB = totalMiB;
            this.freeMiB = freeMiB;
            this.usedMiB = usedMiB;
            this.diskCount = disks.size();
            this.okCount = (int) disks.stream().filter(d -> "ok".equalsIgnoreCase(d.status)).count();
        }

        public double totalTiB() { return totalMiB / 1048576.0; }
        public double freeTiB()  { return freeMiB / 1048576.0; }
        public double usedTiB()  { return usedMiB / 1048576.0; }

        @Override public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("=== HDD Summary ===\n");
            for (Disk d : disks) {
                sb.append(String.format(
                        "Disk[%s] status=%s model=%s total=%.2f GiB free=%.2f GiB used=%.2f GiB%n",
                        d.id, d.status, d.model == null ? "-" : d.model,
                        d.capacityGiB(), d.freeGiB(), d.usedGiB()));
            }
            sb.append(String.format(
                    "TOTAL: %.2f TiB, FREE: %.2f GiB, USED: %.2f GiB%n", totalTiB(), freeTiB(), usedTiB()));
            sb.append(String.format(
                    "Disk count=%d, status=ok count=%d%n",
                    diskCount, okCount));
            return sb.toString();
        }
    }
}
