#Requires -Version 5.1
<#
.SYNOPSIS
    RHOYLLE INNOVATION EMPIRE™ - License Security Module
.DESCRIPTION
    Provides license validation, tamper detection, and security features
.NOTES
    Copyright © 2026 RHOYLLE INNOVATION EMPIRE™. All rights reserved.
    Unauthorized modification or redistribution is prohibited.
#>

# ============================================
# ANTI-TAMPER: Script Hash Validation
# ============================================
$Script:OriginalHash = "HASH_PLACEHOLDER"
$Script:LicenseServerUrl = "https://license.dbaopsframework.com/api/validate"

function Test-ScriptIntegrity {
    <#
    .SYNOPSIS
        Validates that critical scripts haven't been modified
    #>
    param(
        [string]$ScriptPath,
        [string]$ExpectedHash
    )
    
    if (-not (Test-Path $ScriptPath)) { return $false }
    
    $actualHash = (Get-FileHash $ScriptPath -Algorithm SHA256).Hash
    return ($actualHash -eq $ExpectedHash)
}

# ============================================
# LICENSE VALIDATION (Multi-Layer)
# ============================================
function Test-License {
    <#
    .SYNOPSIS
        Validates license key with multiple security layers
    #>
    param(
        [Parameter(Mandatory=$true)]
        [string]$LicenseKey,
        
        [Parameter(Mandatory=$true)]
        [ValidateSet("SQLOpsCenter", "DBAOps", "JBRhoylle")]
        [string]$Product,
        
        [string]$ConfigPath
    )
    
    $result = @{
        IsValid = $false
        LicenseType = "INVALID"
        MaxServers = 0
        ExpirationDate = $null
        Message = ""
        ServerValidated = $false
    }
    
    # Layer 1: Format Validation
    if (-not (Test-LicenseFormat -LicenseKey $LicenseKey -Product $Product)) {
        $result.Message = "Invalid license format"
        return $result
    }
    
    # Layer 2: Checksum Validation
    if (-not (Test-LicenseChecksum -LicenseKey $LicenseKey)) {
        $result.Message = "License checksum failed"
        return $result
    }
    
    # Layer 3: Decode License Data
    $licenseData = Decode-LicenseKey -LicenseKey $LicenseKey
    if (-not $licenseData) {
        $result.Message = "Unable to decode license"
        return $result
    }
    
    # Layer 4: Expiration Check
    if ($licenseData.ExpirationDate -lt (Get-Date)) {
        $result.Message = "License expired on $($licenseData.ExpirationDate.ToString('yyyy-MM-dd'))"
        $result.ExpirationDate = $licenseData.ExpirationDate
        return $result
    }
    
    # Layer 5: Hardware Binding Check (optional)
    if ($licenseData.HardwareBound) {
        $currentHwId = Get-HardwareId
        if ($currentHwId -ne $licenseData.HardwareId) {
            $result.Message = "License not valid for this machine"
            return $result
        }
    }
    
    # Layer 6: Server-Side Validation (if online)
    try {
        $serverResult = Invoke-ServerValidation -LicenseKey $LicenseKey -Product $Product
        if ($serverResult.IsValid) {
            $result.ServerValidated = $true
        } elseif ($serverResult.IsRevoked) {
            $result.Message = "License has been revoked"
            return $result
        }
    } catch {
        # Offline mode - allow with cached validation
        $result.ServerValidated = $false
    }
    
    # All checks passed
    $result.IsValid = $true
    $result.LicenseType = $licenseData.Type
    $result.MaxServers = $licenseData.MaxServers
    $result.ExpirationDate = $licenseData.ExpirationDate
    $result.Message = "License valid"
    
    return $result
}

function Test-LicenseFormat {
    param([string]$LicenseKey, [string]$Product)
    
    $patterns = @{
        "SQLOpsCenter" = "^(TRIAL|SQLOPS-(STR|PRO|ENT|UNL|PERP))-[A-Z0-9]{5}-[A-Z0-9]{5}(-[A-Z0-9]{5})?$"
        "DBAOps"       = "^(TRIAL|DBAOPS-(STR|PRO|ENT|UNL|PERP))-[A-Z0-9]{5}-[A-Z0-9]{5}(-[A-Z0-9]{5})?$"
        "JBRhoylle"    = "^(TRIAL|JBDBA-(STR|PRO|ENT|UNL|PERP))-[A-Z0-9]{5}-[A-Z0-9]{5}(-[A-Z0-9]{5})?$"
    }
    
    return $LicenseKey -match $patterns[$Product]
}

function Test-LicenseChecksum {
    param([string]$LicenseKey)
    
    # Remove dashes and get character codes
    $chars = ($LicenseKey -replace '-','').ToCharArray()
    
    # Calculate checksum (last 2 chars should equal sum of others mod 36)
    $sum = 0
    for ($i = 0; $i -lt ($chars.Length - 2); $i++) {
        $sum += [int][char]$chars[$i]
    }
    
    # Simplified checksum - in production, use more complex algorithm
    return $true  # Placeholder - implement actual checksum
}

function Decode-LicenseKey {
    param([string]$LicenseKey)
    
    $parts = $LicenseKey -split '-'
    
    $typeMap = @{
        "TRIAL" = @{ Type = "TRIAL"; MaxServers = 10; Days = 90 }
        "STR"   = @{ Type = "STARTER"; MaxServers = 10; Days = 365 }
        "PRO"   = @{ Type = "PROFESSIONAL"; MaxServers = 50; Days = 365 }
        "ENT"   = @{ Type = "ENTERPRISE"; MaxServers = 200; Days = 365 }
        "UNL"   = @{ Type = "UNLIMITED"; MaxServers = -1; Days = 365 }
        "PERP"  = @{ Type = "PERPETUAL"; MaxServers = -1; Days = 36500 }
    }
    
    $tier = if ($parts[0] -eq "TRIAL") { "TRIAL" } else { $parts[1] }
    $config = $typeMap[$tier]
    
    if (-not $config) { return $null }
    
    # Decode issue date from key segments (simplified)
    # In production, use encrypted date in key
    $issueDate = Get-Date  # Placeholder
    
    return @{
        Type = $config.Type
        MaxServers = $config.MaxServers
        ExpirationDate = $issueDate.AddDays($config.Days)
        HardwareBound = ($tier -in @("ENT", "UNL", "PERP"))
        HardwareId = $null
    }
}

function Get-HardwareId {
    <#
    .SYNOPSIS
        Generates a unique hardware fingerprint for license binding
    #>
    
    $components = @()
    
    # CPU ID
    try {
        $cpu = Get-CimInstance Win32_Processor | Select-Object -First 1
        $components += $cpu.ProcessorId
    } catch { $components += "CPU_UNKNOWN" }
    
    # Motherboard Serial
    try {
        $mb = Get-CimInstance Win32_BaseBoard | Select-Object -First 1
        $components += $mb.SerialNumber
    } catch { $components += "MB_UNKNOWN" }
    
    # Machine GUID
    try {
        $machineGuid = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Cryptography" -Name MachineGuid).MachineGuid
        $components += $machineGuid
    } catch { $components += "GUID_UNKNOWN" }
    
    # Create hash of combined components
    $combined = $components -join "|"
    $bytes = [System.Text.Encoding]::UTF8.GetBytes($combined)
    $hash = [System.Security.Cryptography.SHA256]::Create().ComputeHash($bytes)
    
    return [System.BitConverter]::ToString($hash).Replace("-", "").Substring(0, 32)
}

function Invoke-ServerValidation {
    param([string]$LicenseKey, [string]$Product)
    
    $body = @{
        LicenseKey = $LicenseKey
        Product = $Product
        HardwareId = Get-HardwareId
        Timestamp = (Get-Date).ToString("o")
    } | ConvertTo-Json
    
    try {
        $response = Invoke-RestMethod -Uri $Script:LicenseServerUrl -Method POST -Body $body -ContentType "application/json" -TimeoutSec 10
        return $response
    } catch {
        return @{ IsValid = $false; Offline = $true }
    }
}

# ============================================
# USAGE TRACKING & ENFORCEMENT
# ============================================
function Get-ServerCount {
    param([string]$ConfigPath)
    
    $configFile = Join-Path $ConfigPath "registered_servers.json"
    if (Test-Path $configFile) {
        $servers = Get-Content $configFile | ConvertFrom-Json
        return $servers.Count
    }
    return 0
}

function Test-ServerLimit {
    param(
        [int]$MaxServers,
        [string]$ConfigPath
    )
    
    if ($MaxServers -eq -1) { return $true }  # Unlimited
    
    $currentCount = Get-ServerCount -ConfigPath $ConfigPath
    return ($currentCount -lt $MaxServers)
}

# ============================================
# ANTI-DEBUG & ANTI-TAMPER
# ============================================
function Test-DebuggerAttached {
    <#
    .SYNOPSIS
        Detects if a debugger is attached to the process
    #>
    
    # Check for common debugging tools
    $debugProcesses = @(
        "devenv", "windbg", "x64dbg", "x32dbg", "ollydbg",
        "ida", "ida64", "dnspy", "ilspy", "dotpeek"
    )
    
    $running = Get-Process -ErrorAction SilentlyContinue | Where-Object { $debugProcesses -contains $_.Name.ToLower() }
    
    return ($null -ne $running)
}

function Protect-ExecutionEnvironment {
    <#
    .SYNOPSIS
        Validates execution environment is safe
    #>
    
    $issues = @()
    
    # Check for debugger
    if (Test-DebuggerAttached) {
        $issues += "Debugger detected"
    }
    
    # Check for VM (optional - may want to allow VMs)
    # $vm = Get-CimInstance Win32_ComputerSystem
    # if ($vm.Model -match "Virtual|VMware|VirtualBox|Hyper-V") {
    #     $issues += "Virtual machine detected"
    # }
    
    # Check PowerShell version
    if ($PSVersionTable.PSVersion.Major -lt 5) {
        $issues += "PowerShell 5.1+ required"
    }
    
    # Check execution policy
    $policy = Get-ExecutionPolicy
    if ($policy -eq "Restricted") {
        $issues += "ExecutionPolicy is Restricted"
    }
    
    return @{
        IsSafe = ($issues.Count -eq 0)
        Issues = $issues
    }
}

# ============================================
# OBFUSCATION HELPERS
# ============================================
function Protect-String {
    param([string]$PlainText)
    
    $secureString = ConvertTo-SecureString $PlainText -AsPlainText -Force
    $encrypted = ConvertFrom-SecureString $secureString
    return $encrypted
}

function Unprotect-String {
    param([string]$EncryptedText)
    
    try {
        $secureString = ConvertTo-SecureString $EncryptedText
        $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
        return [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
    } catch {
        return $null
    }
}

# ============================================
# LICENSE FILE MANAGEMENT
# ============================================
function Save-LicenseFile {
    param(
        [string]$LicenseKey,
        [string]$Product,
        [string]$InstallPath
    )
    
    $licenseData = @{
        LicenseKey = Protect-String -PlainText $LicenseKey
        Product = $Product
        HardwareId = Get-HardwareId
        ActivationDate = (Get-Date).ToString("o")
        LastValidation = (Get-Date).ToString("o")
    }
    
    $licensePath = Join-Path $InstallPath "Config\license.dat"
    $licenseData | ConvertTo-Json | Out-File $licensePath -Encoding UTF8
    
    # Set file as hidden and system
    $file = Get-Item $licensePath -Force
    $file.Attributes = "Hidden,System"
    
    return $licensePath
}

function Read-LicenseFile {
    param([string]$InstallPath)
    
    $licensePath = Join-Path $InstallPath "Config\license.dat"
    
    if (-not (Test-Path $licensePath)) {
        return $null
    }
    
    try {
        $licenseData = Get-Content $licensePath -Force | ConvertFrom-Json
        $licenseData.LicenseKey = Unprotect-String -EncryptedText $licenseData.LicenseKey
        return $licenseData
    } catch {
        return $null
    }
}

# ============================================
# EXPORT FUNCTIONS
# ============================================
Export-ModuleMember -Function @(
    'Test-License',
    'Test-ScriptIntegrity',
    'Get-HardwareId',
    'Test-ServerLimit',
    'Protect-ExecutionEnvironment',
    'Save-LicenseFile',
    'Read-LicenseFile'
)
