using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using AxCopilot.Views;

namespace AxCopilot.Security;

/// <summary>
/// 런타임 디컴파일/디버깅 방지 모듈.
/// - 디버거 감지 (관리형 + 네이티브)
/// - 알려진 디컴파일러 프로세스 감지
/// - 어셈블리 무결성 검증
/// </summary>
internal static class AntiTamper
{
    [DllImport("kernel32.dll")]
    private static extern bool IsDebuggerPresent();

    [DllImport("kernel32.dll")]
    private static extern bool CheckRemoteDebuggerPresent(IntPtr hProcess, ref bool isDebuggerPresent);

    /// <summary>보안 감지를 건너뛰는 사내 IP 대역 (프리픽스 매칭)</summary>
    private static readonly string[] TrustedIpPrefixes =
    [
        "11.99.", "11.90.", "11.96.", "12.25.", "12.23.", "12.24."
    ];

    /// <summary>알려진 .NET 디컴파일러/리버싱 도구 프로세스명</summary>
    private static readonly string[] KnownDebuggers =
    [
        "dnspy", "dnspy-x86", "ilspy", "dotpeek", "de4dot",
        "ollydbg", "x64dbg", "x32dbg", "windbg",
        "ida", "ida64", "ghidra", "cheatengine",
        "processhacker", "fiddler", "wireshark"
    ];

    /// <summary>
    /// 앱 시작 시 호출. 디버거/디컴파일러가 감지되면 경고 후 종료합니다.
    /// Release 빌드에서만 활성화됩니다.
    /// </summary>
    public static void Check()
    {
#if !DEBUG
        // 사내 네트워크(신뢰 IP 대역)에서는 보안 감지 건너뛰기
        if (IsTrustedNetwork()) return;

        if (IsBeingDebugged())
        {
            CustomMessageBox.Show(
                "보안 정책에 의해 디버거가 연결된 상태에서는 실행할 수 없습니다.",
                "AX Copilot — 보안",
                System.Windows.MessageBoxButton.OK,
                System.Windows.MessageBoxImage.Warning);
            Environment.Exit(1);
        }

        if (IsDecompilerRunning())
        {
            CustomMessageBox.Show(
                "보안 정책에 의해 리버싱 도구가 실행 중인 환경에서는 실행할 수 없습니다.",
                "AX Copilot — 보안",
                System.Windows.MessageBoxButton.OK,
                System.Windows.MessageBoxImage.Warning);
            Environment.Exit(1);
        }
#endif
    }

    /// <summary>관리형 + 네이티브 디버거 감지</summary>
    private static bool IsBeingDebugged()
    {
        // 1. 관리형 디버거 (.NET Attach)
        if (Debugger.IsAttached) return true;

        // 2. 네이티브 디버거 (OllyDbg, x64dbg 등)
        try { if (IsDebuggerPresent()) return true; } catch (Exception) { }

        // 3. 원격 디버거
        try
        {
            bool remoteDebugger = false;
            CheckRemoteDebuggerPresent(Process.GetCurrentProcess().Handle, ref remoteDebugger);
            if (remoteDebugger) return true;
        }
        catch (Exception) { }

        return false;
    }

    /// <summary>알려진 디컴파일러/리버싱 프로세스가 실행 중인지 확인</summary>
    private static bool IsDecompilerRunning()
    {
        try
        {
            var procs = Process.GetProcesses();
            foreach (var proc in procs)
            {
                try
                {
                    var name = proc.ProcessName.ToLowerInvariant();
                    foreach (var debugger in KnownDebuggers)
                    {
                        if (name.Contains(debugger))
                            return true;
                    }
                }
                catch (Exception) { /* 접근 권한 없는 프로세스 무시 */ }
            }
        }
        catch (Exception) { }
        return false;
    }

    /// <summary>현재 PC의 IP가 사내 신뢰 대역에 포함되는지 확인</summary>
    private static bool IsTrustedNetwork()
    {
        try
        {
            var addresses = Dns.GetHostAddresses(Dns.GetHostName());
            foreach (var addr in addresses)
            {
                if (addr.AddressFamily != AddressFamily.InterNetwork) continue;
                var ip = addr.ToString();
                foreach (var prefix in TrustedIpPrefixes)
                {
                    if (ip.StartsWith(prefix))
                        return true;
                }
            }
        }
        catch (Exception) { /* 네트워크 조회 실패 시 신뢰하지 않음 */ }
        return false;
    }

    /// <summary>
    /// 어셈블리 강력한 이름(Strong Name) 검증.
    /// 서명된 어셈블리가 변조되었는지 간단히 확인합니다.
    /// </summary>
    public static bool VerifyAssemblyIntegrity()
    {
        try
        {
            var asm = Assembly.GetExecutingAssembly();
            var name = asm.GetName();
            // 버전이 변조되지 않았는지 기본 확인
            return name.Version != null && name.Name == "AxCopilot";
        }
        catch (Exception)
        {
            return false;
        }
    }
}
