using System.Diagnostics;
using System.Net.NetworkInformation;
using ArpLookup;
using System.Runtime.InteropServices;
using System.Net;
using System.Text.RegularExpressions;

/// <summary>
/// ARP 记录管理静态类（跨平台支持）
/// </summary>
public static class ArpClient
{
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    /// <summary>
    /// 读取所有 ARP 记录
    /// </summary>
    /// <returns>ARP 记录列表</returns>
    public static async Task<List<ArpEntry>> GetArpTableAsync()
    {
        var entries = new List<ArpEntry>();

        try
        {
            string command = GetArpListCommand();
            var result = await ExecuteCommandAsync(command);
            if (result.IsSuccess)
            {
                var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);

                foreach (var line in lines)
                {
                    var entry = ParseArpEntry(line);
                    if (entry != null)
                    {
                        entries.Add(entry);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception($"读取 ARP 表失败: {ex.Message}");
        }

        return entries;
    }

    /// <summary>
    /// 动态更新指定 IP 的 ARP 记录
    /// </summary>
    /// <param name="ipAddress">要更新的 IP 地址</param>
    /// <returns>是否成功发送 Ping</returns>
    public static async Task<bool> UpdateArpEntryAsync(string ipAddress)
    {
        if (string.IsNullOrWhiteSpace(ipAddress))
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));

        try
        {
            var ret = await ArpClient.DeleteArpEntryAsync(ipAddress);
            if (!ret)
            {
                logger.Error($"删除 ARP 记录失败: {ipAddress}");
            }

            PhysicalAddress? mac = await Arp.LookupAsync(IPAddress.Parse(ipAddress));
            if (mac == null)
                return false;

            return true;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 添加 ARP 记录
    /// </summary>
    /// <param name="ipAddress">IP 地址</param>
    /// <param name="macAddress">MAC 地址</param>
    /// <param name="interfaceName">网络接口名称（可选）</param>
    /// <returns>是否成功</returns>
    public static async Task<bool> AddArpEntryAsync(string ipAddress, string macAddress, string? interfaceName = null)
    {
        if (string.IsNullOrWhiteSpace(ipAddress))
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));

        if (string.IsNullOrWhiteSpace(macAddress))
            throw new ArgumentException("MAC 地址不能为空", nameof(macAddress));

        try
        {
            // 格式化 MAC 地址以适配不同操作系统
            string formattedMac = FormatMacAddress(macAddress);
            string command = await GetArpAddCommandAsync(ipAddress, formattedMac, interfaceName);
            var result = await ExecuteCommandAsync(command);
            return result.IsSuccess;
        }
        catch (Exception ex)
        {
            throw new Exception($"添加 ARP 记录失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 删除 ARP 记录
    /// </summary>
    /// <param name="ipAddress">要删除的 IP 地址</param>
    /// <param name="interfaceName">网络接口名称（可选）</param>
    /// <returns>是否成功</returns>
    public static async Task<bool> DeleteArpEntryAsync(string ipAddress, string? interfaceName = null)
    {
        if (string.IsNullOrWhiteSpace(ipAddress))
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));

        try
        {
            string command = GetArpDeleteCommand(ipAddress, interfaceName);
            var result = await ExecuteCommandAsync(command);
            return result.IsSuccess;
        }
        catch (Exception ex)
        {
            throw new Exception($"删除 ARP 记录失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 清空所有 ARP 记录
    /// </summary>
    /// <returns>是否成功</returns>
    public static async Task<bool> ClearArpTableAsync()
    {
        try
        {
            string command = GetArpClearCommand();
            var result = await ExecuteCommandAsync(command);
            return result.IsSuccess;
        }
        catch (Exception ex)
        {
            throw new Exception($"清空 ARP 表失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 查询特定 IP 的 ARP 记录
    /// </summary>
    /// <param name="ipAddress">IP 地址</param>
    /// <returns>ARP 记录，如果不存在则返回 null</returns>
    public static async Task<ArpEntry?> GetArpEntryAsync(string ipAddress)
    {
        if (string.IsNullOrWhiteSpace(ipAddress))
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));

        try
        {
            string command = GetArpQueryCommand(ipAddress);
            var result = await ExecuteCommandAsync(command);
            if (result.IsSuccess)
            {
                var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);
                foreach (var line in lines)
                {
                    var entry = ParseArpEntry(line);
                    if (entry != null && entry.IpAddress == ipAddress)
                    {
                        return entry;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception($"查询 ARP 记录失败: {ex.Message}");
        }

        return null;
    }

    /// <summary>
    /// 获取 ARP 列表命令
    /// </summary>
    private static string GetArpListCommand()
    {
        return "arp -a";
    }

    /// <summary>
    /// 获取 ARP 添加命令
    /// </summary>
    private static async Task<string> GetArpAddCommandAsync(string ipAddress, string macAddress, string? interfaceName)
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            if (!string.IsNullOrWhiteSpace(interfaceName))
            {
                // 通过 arp -a 获取接口索引
                var interfaceIdx = await GetWindowsInterfaceIndexAsync(interfaceName);
                if (interfaceIdx.HasValue)
                {
                    return $"netsh -c i i add neighbors {interfaceIdx.Value} {ipAddress} {macAddress}";
                }
            }
            return $"arp -s {ipAddress} {macAddress}";
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            return string.IsNullOrWhiteSpace(interfaceName)
                ? $"arp -s {ipAddress} {macAddress}"
                : $"arp -s {ipAddress} {macAddress} -i {interfaceName}";
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            return string.IsNullOrWhiteSpace(interfaceName)
                ? $"arp -s {ipAddress} {macAddress}"
                : $"arp -s {ipAddress} {macAddress} ifscope {interfaceName}";
        }
        else
        {
            throw new PlatformNotSupportedException("不支持的操作系统平台");
        }
    }

    /// <summary>
    /// 获取 Windows 接口索引
    /// </summary>
    /// <param name="interfaceIp">接口IP地址</param>
    /// <returns>接口索引（十进制），如果未找到则返回null</returns>
    private static async Task<int?> GetWindowsInterfaceIndexAsync(string interfaceIp)
    {
        try
        {
            var result = await ExecuteCommandAsync("arp -a");
            if (!result.IsSuccess)
                return null;

            var lines = result.Output.Split('\n', StringSplitOptions.RemoveEmptyEntries);

            foreach (var line in lines)
            {
                // 匹配接口行格式: Interface: 172.6.1.5 --- 0xa
                var interfacePattern = @"Interface:\s+(\d+\.\d+\.\d+\.\d+)\s+---\s+(0x[a-fA-F0-9]+)";
                var match = Regex.Match(line, interfacePattern);

                if (match.Success && match.Groups[1].Value == interfaceIp)
                {
                    // 将十六进制索引转换为十进制
                    var hexIndex = match.Groups[2].Value;
                    // 去掉 "0x" 前缀
                    var hexValue = hexIndex.StartsWith("0x", StringComparison.OrdinalIgnoreCase)
                        ? hexIndex.Substring(2)
                        : hexIndex;

                    if (int.TryParse(hexValue, System.Globalization.NumberStyles.HexNumber, null, out int decimalIndex))
                    {
                        logger.Debug($"找到接口 {interfaceIp} 的索引: {hexIndex} -> {decimalIndex}");
                        return decimalIndex;
                    }
                }
            }

            logger.Warn($"未找到接口 {interfaceIp} 的索引");
            return null;
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"获取接口 {interfaceIp} 索引失败");
            return null;
        }
    }

    /// <summary>
    /// 获取 ARP 删除命令
    /// </summary>
    private static string GetArpDeleteCommand(string ipAddress, string? interfaceName)
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            return $"arp -d {ipAddress}";
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            return string.IsNullOrWhiteSpace(interfaceName)
                ? $"arp -d {ipAddress}"
                : $"arp -d {ipAddress} -i {interfaceName}";
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            return string.IsNullOrWhiteSpace(interfaceName)
                ? $"arp -d {ipAddress}"
                : $"arp -d {ipAddress} ifscope {interfaceName}";
        }
        else
        {
            throw new PlatformNotSupportedException("不支持的操作系统平台");
        }
    }

    /// <summary>
    /// 获取 ARP 清空命令
    /// </summary>
    private static string GetArpClearCommand()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            return "arp -d *";
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            return "ip neigh flush all";
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            return "arp -d -a";
        }
        else
        {
            throw new PlatformNotSupportedException("不支持的操作系统平台");
        }
    }

    /// <summary>
    /// 获取 ARP 查询命令
    /// </summary>
    private static string GetArpQueryCommand(string ipAddress)
    {
        return $"arp -a {ipAddress}";
    }

    /// <summary>
    /// 执行系统命令
    /// </summary>
    /// <param name="command">命令</param>
    /// <returns>命令执行结果</returns>
    private static async Task<CommandResult> ExecuteCommandAsync(string command)
    {
        try
        {
            ProcessStartInfo processInfo;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                processInfo = new ProcessStartInfo
                {
                    FileName = "cmd.exe",
                    Arguments = $"/c {command}",
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };
            }
            else
            {
                processInfo = new ProcessStartInfo
                {
                    FileName = "/bin/bash",
                    Arguments = $"-c \"{command}\"",
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };
            }

            logger.Debug($"Executing command: {processInfo.FileName} {processInfo.Arguments}");

            using var process = new Process { StartInfo = processInfo };
            process.Start();

            var output = await process.StandardOutput.ReadToEndAsync();
            var error = await process.StandardError.ReadToEndAsync();

            await process.WaitForExitAsync();

            logger.Debug($"Command output: {output}");
            if (!string.IsNullOrWhiteSpace(error))
                logger.Debug($"Command error: {error}");
            logger.Debug($"Command exit code: {process.ExitCode}");

            return new CommandResult
            {
                IsSuccess = process.ExitCode == 0,
                Output = output,
                Error = error,
                ExitCode = process.ExitCode
            };
        }
        catch (Exception ex)
        {
            logger.Error(ex, $"Command execution failed: {command}");
            return new CommandResult
            {
                IsSuccess = false,
                Error = ex.Message,
                ExitCode = -1
            };
        }
    }

    /// <summary>
    /// 解析 ARP 记录行
    /// </summary>
    /// <param name="line">ARP 记录行</param>
    /// <returns>解析后的 ARP 记录</returns>
    private static ArpEntry? ParseArpEntry(string line)
    {
        if (string.IsNullOrWhiteSpace(line))
            return null;

        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            return ParseWindowsArpEntry(line);
        }
        else
        {
            return ParseUnixArpEntry(line);
        }
    }

    /// <summary>
    /// 解析 Windows ARP 记录
    /// </summary>
    private static ArpEntry? ParseWindowsArpEntry(string line)
    {
        // 跳过空行和标题行
        if (string.IsNullOrWhiteSpace(line) ||
            line.Contains("Interface:") ||
            line.Contains("Internet Address") ||
            line.Contains("Physical Address") ||
            line.Contains("Type"))
        {
            return null;
        }

        // Windows arp -a 输出格式: IP地址 物理地址 类型
        // 示例: 172.6.0.1             e4-3a-6e-29-c3-5b     dynamic
        var pattern = @"^\s*(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9-]{17})\s+(\w+)\s*$";
        var match = Regex.Match(line, pattern);

        if (match.Success)
        {
            return new ArpEntry
            {
                IpAddress = match.Groups[1].Value,
                MacAddress = FormatMacAddress(match.Groups[2].Value), // 格式化 MAC 地址
                Type = match.Groups[3].Value
            };
        }

        return null;
    }

    /// <summary>
    /// 解析 Unix/Linux ARP 记录
    /// </summary>
    private static ArpEntry? ParseUnixArpEntry(string line)
    {
        // Unix/Linux arp -a 输出格式: hostname (ip) at mac [ether] PERM on interface
        var pattern = @"(\S+)\s+\((\d+\.\d+\.\d+\.\d+)\)\s+at\s+([a-fA-F0-9:]{17})\s+\[(\w+)\]\s+(\w+)\s+on\s+(\S+)";
        var match = Regex.Match(line, pattern);

        if (match.Success)
        {
            return new ArpEntry
            {
                Hostname = match.Groups[1].Value,
                IpAddress = match.Groups[2].Value,
                MacAddress = FormatMacAddress(match.Groups[3].Value), // 格式化 MAC 地址
                Type = match.Groups[5].Value,
                Interface = match.Groups[6].Value
            };
        }

        // 匹配简单格式: ip mac interface
        var simplePattern = @"(\d+\.\d+\.\d+\.\d+)\s+([a-fA-F0-9:]{17})\s+(\S+)";
        var simpleMatch = Regex.Match(line, simplePattern);

        if (simpleMatch.Success)
        {
            return new ArpEntry
            {
                IpAddress = simpleMatch.Groups[1].Value,
                MacAddress = FormatMacAddress(simpleMatch.Groups[2].Value), // 格式化 MAC 地址
                Interface = simpleMatch.Groups[3].Value
            };
        }

        return null;
    }

    /// <summary>
    /// 判断当前进程是否具有管理员（或 root）权限
    /// </summary>
    /// <returns>如果有管理员权限返回 true，否则返回 false</returns>
    public static bool IsAdministrator()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            // Windows: 检查当前用户是否为管理员
            using var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
            var principal = new System.Security.Principal.WindowsPrincipal(identity);
            return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
        }
        else
        {
            // Unix/Linux/macOS: 检查是否为 root 用户
            return Environment.UserName == "root" || (Environment.GetEnvironmentVariable("USER") == "root");
        }
    }

    /// <summary>
    /// 检查指定 IP 是否存在对应的 MAC，如果不存在则删除原有 ARP 记录并新增
    /// </summary>
    /// <param name="ipAddress">IP 地址</param>
    /// <param name="macAddress">MAC 地址</param>
    /// <param name="interfaceName">网络接口名称（可选）</param>
    /// <returns>是否成功</returns>
    public static async Task<bool> CheckOrAddAsync(string ipAddress, string macAddress, string? interfaceName = null)
    {
        if (string.IsNullOrWhiteSpace(ipAddress))
            throw new ArgumentException("IP 地址不能为空", nameof(ipAddress));
        if (string.IsNullOrWhiteSpace(macAddress))
            throw new ArgumentException("MAC 地址不能为空", nameof(macAddress));

        // 格式化 MAC 地址以适配不同操作系统
        string formattedMac = FormatMacAddress(macAddress);

        var entry = await GetArpEntryAsync(ipAddress);
        if (entry != null && string.Equals(FormatMacAddress(entry.MacAddress), formattedMac, StringComparison.OrdinalIgnoreCase))
        {
            // 已存在且 MAC 匹配，无需操作
            return true;
        }

        // 若存在但 MAC 不匹配，先删除
        if (entry != null)
        {
            await DeleteArpEntryAsync(ipAddress, interfaceName);
        }

        // 新增 ARP 记录
        var ret = await AddArpEntryAsync(ipAddress, formattedMac, interfaceName);
        if (!ret) logger.Error($"添加 ARP 记录失败: {ipAddress} -> {formattedMac} on {interfaceName}");
        return true;
    }

    /// <summary>
    /// 格式化 MAC 地址为指定平台格式
    /// </summary>
    /// <param name="macAddress">原始 MAC 地址</param>
    /// <returns>格式化后的 MAC 地址</returns>
    public static string FormatMacAddress(string macAddress)
    {
        if (string.IsNullOrWhiteSpace(macAddress))
            return string.Empty;

        var cleaned = macAddress.Replace("-", "").Replace(":", "").ToLowerInvariant();
        if (cleaned.Length != 12)
            return macAddress;

        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            // Windows: XX-XX-XX-XX-XX-XX
            return string.Join("-", Enumerable.Range(0, 6).Select(i => cleaned.Substring(i * 2, 2)));
        }
        else
        {
            // Unix/Linux/macOS: xx:xx:xx:xx:xx:xx
            return string.Join(":", Enumerable.Range(0, 6).Select(i => cleaned.Substring(i * 2, 2)));
        }
    }
}
/// <summary>
/// ARP 记录条目
/// </summary>
public class ArpEntry
{
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string Hostname { get; set; } = string.Empty;
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string IpAddress { get; set; } = string.Empty;
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string MacAddress { get; set; } = string.Empty;
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string Type { get; set; } = string.Empty;
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string Interface { get; set; } = string.Empty;

    /// <summary>
    /// [TODO:description]
    /// </summary>
    public override string ToString()
    {
        return $"{IpAddress} -> {MacAddress} ({Interface})";
    }
}

/// <summary>
/// 命令执行结果
/// </summary>
public class CommandResult
{
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public bool IsSuccess { get; set; }
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string Output { get; set; } = string.Empty;
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public string Error { get; set; } = string.Empty;
    /// <summary>
    /// [TODO:description]
    /// </summary>
    public int ExitCode { get; set; }
}
