package tech.easyflow.autoconfig.license;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.io.DefaultResourceLoader;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

/**
 * {@link MachineIdentityCollector} 测试。
 */
public class MachineIdentityCollectorTest {

    /**
     * Linux 采集命令应按约定返回三项机器参数。
     */
    @Test
    public void shouldCollectLinuxIdentity() {
        TestMachineIdentityCollector collector = new TestMachineIdentityCollector("Linux");
        collector.shellOutputs.put("cat /etc/machine-id", "linux-machine");
        collector.shellOutputs.put("cat /sys/class/dmi/id/product_uuid", "linux-product");
        collector.shellOutputs.put("cat /sys/class/net/$(ip route | awk '/default/ {print $5; exit}')/address", "aa:bb:cc:dd:ee:ff");

        MachineIdentity identity = collector.collect();
        Assert.assertEquals("linux-machine", identity.machineId());
        Assert.assertEquals("linux-product", identity.productUuid());
        Assert.assertEquals("aa:bb:cc:dd:ee:ff", identity.macAddresses());
    }

    /**
     * macOS 采集命令应按约定返回三项机器参数。
     */
    @Test
    public void shouldCollectMacIdentity() {
        TestMachineIdentityCollector collector = new TestMachineIdentityCollector("Mac OS X");
        collector.shellOutputs.put("ioreg -rd1 -c IOPlatformExpertDevice | awk -F'\"' '/IOPlatformUUID/ {print $(NF-1)}'", "mac-platform-uuid");
        collector.shellOutputs.put("networksetup -listallhardwareports | awk '/Device/ {device=$2} /Ethernet Address/ {print $3; exit}'", "AA-BB-CC-DD-EE-FF");

        MachineIdentity identity = collector.collect();
        Assert.assertEquals("mac-platform-uuid", identity.machineId());
        Assert.assertEquals("mac-platform-uuid", identity.productUuid());
        Assert.assertEquals("AA-BB-CC-DD-EE-FF", identity.macAddresses());
    }

    /**
     * Windows 采集命令应按约定返回三项机器参数。
     */
    @Test
    public void shouldCollectWindowsIdentity() {
        TestMachineIdentityCollector collector = new TestMachineIdentityCollector("Windows 11");
        collector.powerShellOutputs.put("(Get-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Cryptography').MachineGuid", "windows-machine");
        collector.powerShellOutputs.put("(Get-CimInstance Win32_ComputerSystemProduct).UUID", "windows-product");
        collector.powerShellOutputs.put("(Get-NetAdapter | Where-Object {$_.Status -eq 'Up' -and $_.MacAddress} | Select-Object -First 1 -ExpandProperty MacAddress)", "AA-BB-CC-DD-EE-FF");

        MachineIdentity identity = collector.collect();
        Assert.assertEquals("windows-machine", identity.machineId());
        Assert.assertEquals("windows-product", identity.productUuid());
        Assert.assertEquals("AA-BB-CC-DD-EE-FF", identity.macAddresses());
    }

    /**
     * 已配置的覆盖文件应优先于系统命令。
     *
     * @throws Exception 创建临时文件失败
     */
    @Test
    public void shouldPreferConfiguredIdentityFiles() throws Exception {
        Path tempDir = Files.createTempDirectory("machine-identity-collector");
        Path machineIdFile = tempDir.resolve("machine-id.txt");
        Path productUuidFile = tempDir.resolve("product-uuid.txt");
        Path macAddressFile = tempDir.resolve("mac-address.txt");
        Files.writeString(machineIdFile, "mounted-machine\n", StandardCharsets.UTF_8);
        Files.writeString(productUuidFile, "mounted-product\n", StandardCharsets.UTF_8);
        Files.writeString(macAddressFile, "02:42:ac:20:00:11\n", StandardCharsets.UTF_8);

        TestMachineIdentityCollector collector = new TestMachineIdentityCollector(
                "Linux",
                new DefaultResourceLoader(),
                machineIdFile.toUri().toString(),
                productUuidFile.toUri().toString(),
                macAddressFile.toUri().toString()
        );

        MachineIdentity identity = collector.collect();
        Assert.assertEquals("mounted-machine", identity.machineId());
        Assert.assertEquals("mounted-product", identity.productUuid());
        Assert.assertEquals("02:42:ac:20:00:11", identity.macAddresses());
    }

    /**
     * 空输出应被识别为采集失败。
     */
    @Test
    public void shouldFailWhenCommandOutputIsBlank() {
        TestMachineIdentityCollector collector = new TestMachineIdentityCollector("Linux");
        collector.shellOutputs.put("cat /etc/machine-id", "");

        try {
            collector.collect();
            Assert.fail("预期应抛出异常");
        } catch (IllegalStateException ex) {
            Assert.assertTrue(ex.getMessage().contains("输出为空"));
        }
    }

    /**
     * 测试用机器信息采集器。
     */
    private static class TestMachineIdentityCollector extends MachineIdentityCollector {

        private final String osName;
        private final Map<String, String> shellOutputs = new HashMap<>();
        private final Map<String, String> powerShellOutputs = new HashMap<>();

        private TestMachineIdentityCollector(String osName) {
            this(osName, new DefaultResourceLoader(), null, null, null);
        }

        private TestMachineIdentityCollector(String osName,
                                             DefaultResourceLoader resourceLoader,
                                             String machineIdFile,
                                             String productUuidFile,
                                             String macAddressFile) {
            super(resourceLoader, machineIdFile, productUuidFile, macAddressFile);
            this.osName = osName;
        }

        /**
         * 返回固定的操作系统名称。
         *
         * @return 操作系统名称
         */
        @Override
        protected String currentOsName() {
            return osName;
        }

        /**
         * 返回预设 shell 输出。
         *
         * @param description 描述
         * @param command 命令
         * @return 命令输出
         */
        @Override
        protected String executeShellCommand(String description, String command) {
            return lookupOutput(description, command, shellOutputs);
        }

        /**
         * 返回预设 PowerShell 输出。
         *
         * @param description 描述
         * @param command 命令
         * @return 命令输出
         */
        @Override
        protected String executePowerShellCommand(String description, String command) {
            return lookupOutput(description, command, powerShellOutputs);
        }

        private String lookupOutput(String description, String command, Map<String, String> outputs) {
            if (!outputs.containsKey(command)) {
                throw new IllegalStateException(description + "失败，命令未配置输出");
            }
            String output = outputs.get(command);
            if (output == null || output.trim().isEmpty()) {
                throw new IllegalStateException(description + "失败，输出为空");
            }
            return output;
        }
    }
}
