using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Synor.Compiler;

// ============================================================================
// Enumerations
// ============================================================================

/// <summary>Optimization level for WASM compilation.</summary>
public enum OptimizationLevel
{
    /// <summary>No optimization.</summary>
    None,
    /// <summary>Basic optimizations (stripping only).</summary>
    Basic,
    /// <summary>Optimize for size (-Os equivalent).</summary>
    Size,
    /// <summary>Aggressive optimization (-O3 -Os equivalent).</summary>
    Aggressive
}

public static class OptimizationLevelExtensions
{
    public static string ToApiString(this OptimizationLevel level) => level switch
    {
        OptimizationLevel.None => "none",
        OptimizationLevel.Basic => "basic",
        OptimizationLevel.Size => "size",
        OptimizationLevel.Aggressive => "aggressive",
        _ => "size"
    };

    public static OptimizationLevel FromApiString(string value) => value switch
    {
        "none" => OptimizationLevel.None,
        "basic" => OptimizationLevel.Basic,
        "size" => OptimizationLevel.Size,
        "aggressive" => OptimizationLevel.Aggressive,
        _ => OptimizationLevel.Size
    };
}

// ============================================================================
// Configuration
// ============================================================================

/// <summary>Strip options for WASM sections.</summary>
public record StripOptions
{
    public bool StripDebug { get; init; } = true;
    public bool StripProducers { get; init; } = true;
    public bool StripNames { get; init; } = true;
    public bool StripCustom { get; init; } = true;
    public List<string> PreserveSections { get; init; } = new();
    public bool StripUnused { get; init; } = true;
}

/// <summary>Compiler configuration.</summary>
public record CompilerConfig
{
    public required string ApiKey { get; init; }
    public string Endpoint { get; init; } = "https://compiler.synor.io/v1";
    public int Timeout { get; init; } = 60000;
    public int Retries { get; init; } = 3;
    public bool Debug { get; init; } = false;
    public OptimizationLevel DefaultOptimizationLevel { get; init; } = OptimizationLevel.Size;
    public StripOptions? StripOptions { get; init; }
    public int MaxContractSize { get; init; } = 256 * 1024;
    public bool UseWasmOpt { get; init; } = true;
    public bool Validate { get; init; } = true;
    public bool ExtractMetadata { get; init; } = true;
    public bool GenerateAbi { get; init; } = true;
}

/// <summary>Compilation request.</summary>
public record CompilationRequest
{
    public OptimizationLevel? OptimizationLevel { get; init; }
    public StripOptions? StripOptions { get; init; }
    public bool? UseWasmOpt { get; init; }
    public bool? Validate { get; init; }
    public bool? ExtractMetadata { get; init; }
    public bool? GenerateAbi { get; init; }
}

// ============================================================================
// Validation Types
// ============================================================================

/// <summary>Validation error.</summary>
public record ValidationError
{
    public string Code { get; init; } = "";
    public string Message { get; init; } = "";
    public string? Location { get; init; }
}

/// <summary>Validation result.</summary>
public record ValidationResult
{
    public bool Valid { get; init; }
    public List<ValidationError>? Errors { get; init; }
    public List<string>? Warnings { get; init; }
    public int ExportCount { get; init; }
    public int ImportCount { get; init; }
    public int FunctionCount { get; init; }
    public int[]? MemoryPages { get; init; }
}

// ============================================================================
// Metadata Types
// ============================================================================

/// <summary>Contract metadata.</summary>
public record ContractMetadata
{
    public string? Name { get; init; }
    public string? Version { get; init; }
    public List<string>? Authors { get; init; }
    public string? Description { get; init; }
    public string? License { get; init; }
    public string? Repository { get; init; }
    public long? BuildTimestamp { get; init; }
    public string? RustVersion { get; init; }
    public string? SdkVersion { get; init; }
    public Dictionary<string, string>? Custom { get; init; }
}

// ============================================================================
// ABI Types
// ============================================================================

/// <summary>Type information.</summary>
public record TypeInfo
{
    public string Kind { get; init; } = "unknown";
    public int? Size { get; init; }
    public TypeInfo? Element { get; init; }
    public TypeInfo? Inner { get; init; }
    public List<TypeInfo>? Elements { get; init; }
    public string? Name { get; init; }
    public List<TypeField>? Fields { get; init; }

    public string TypeName => Kind switch
    {
        "u8" or "u16" or "u32" or "u64" or "u128" or
        "i8" or "i16" or "i32" or "i64" or "i128" or
        "bool" or "string" or "bytes" or "address" or "hash256" => Kind,
        "fixedBytes" => $"bytes{Size ?? 0}",
        "array" => $"{Element?.TypeName ?? ""}[]",
        "fixedArray" => $"{Element?.TypeName ?? ""}[{Size ?? 0}]",
        "option" => $"{Inner?.TypeName ?? ""}?",
        "tuple" => $"({string.Join(", ", Elements?.ConvertAll(e => e.TypeName) ?? new())})",
        "struct" => Name ?? "struct",
        _ => Name ?? "unknown"
    };
}

/// <summary>Type field for structs.</summary>
public record TypeField(string Name, TypeInfo Type);

/// <summary>Parameter ABI.</summary>
public record ParamAbi
{
    public string Name { get; init; } = "";
    public TypeInfo Type { get; init; } = new();
    public bool Indexed { get; init; }
}

/// <summary>Function ABI.</summary>
public record FunctionAbi
{
    public string Name { get; init; } = "";
    public string Selector { get; init; } = "";
    public List<ParamAbi>? Inputs { get; init; }
    public List<ParamAbi>? Outputs { get; init; }
    public bool View { get; init; }
    public bool Payable { get; init; }
    public string? Doc { get; init; }
}

/// <summary>Event ABI.</summary>
public record EventAbi
{
    public string Name { get; init; } = "";
    public string Topic { get; init; } = "";
    public List<ParamAbi>? Params { get; init; }
    public string? Doc { get; init; }
}

/// <summary>Error ABI.</summary>
public record ErrorAbi
{
    public string Name { get; init; } = "";
    public string Selector { get; init; } = "";
    public List<ParamAbi>? Params { get; init; }
    public string? Doc { get; init; }
}

/// <summary>Contract ABI (Application Binary Interface).</summary>
public record ContractAbi
{
    public string Name { get; init; } = "";
    public string Version { get; init; } = "1.0.0";
    public List<FunctionAbi>? Functions { get; init; }
    public List<EventAbi>? Events { get; init; }
    public List<ErrorAbi>? Errors { get; init; }

    public FunctionAbi? FindFunction(string name) =>
        Functions?.Find(f => f.Name == name);

    public FunctionAbi? FindBySelector(string selector) =>
        Functions?.Find(f => f.Selector == selector);
}

// ============================================================================
// Compilation Types
// ============================================================================

/// <summary>Compilation result.</summary>
public record CompilationResult
{
    public string ContractId { get; init; } = "";
    public string Code { get; init; } = "";
    public string CodeHash { get; init; } = "";
    public int OriginalSize { get; init; }
    public int OptimizedSize { get; init; }
    public double SizeReduction { get; init; }
    public ContractMetadata? Metadata { get; init; }
    public ContractAbi? Abi { get; init; }
    public long EstimatedDeployGas { get; init; }
    public ValidationResult? Validation { get; init; }
    public List<string>? Warnings { get; init; }

    public string SizeStats =>
        $"Original: {OriginalSize} bytes, Optimized: {OptimizedSize} bytes, Reduction: {SizeReduction:F1}%";

    public byte[] DecodeCode() => Convert.FromBase64String(Code);
}

// ============================================================================
// Analysis Types
// ============================================================================

/// <summary>Size breakdown.</summary>
public record SizeBreakdown
{
    public int Code { get; init; }
    public int Data { get; init; }
    public int Types { get; init; }
    public int Functions { get; init; }
    public int Memory { get; init; }
    public int Table { get; init; }
    public int Exports { get; init; }
    public int Imports { get; init; }
    public int Custom { get; init; }
    public int Total { get; init; }
}

/// <summary>Function analysis.</summary>
public record FunctionAnalysis
{
    public string Name { get; init; } = "";
    public int Size { get; init; }
    public int InstructionCount { get; init; }
    public int LocalCount { get; init; }
    public bool Exported { get; init; }
    public long EstimatedGas { get; init; }
}

/// <summary>Import analysis.</summary>
public record ImportAnalysis
{
    public string Module { get; init; } = "";
    public string Name { get; init; } = "";
    public string Kind { get; init; } = "function";
    public string? Signature { get; init; }
}

/// <summary>Security issue.</summary>
public record SecurityIssue
{
    public string Severity { get; init; } = "low";
    public string Type { get; init; } = "";
    public string Description { get; init; } = "";
    public string? Location { get; init; }
}

/// <summary>Security analysis.</summary>
public record SecurityAnalysis
{
    public int Score { get; init; }
    public List<SecurityIssue>? Issues { get; init; }
    public List<string>? Recommendations { get; init; }
}

/// <summary>Gas analysis.</summary>
public record GasAnalysis
{
    public long DeploymentGas { get; init; }
    public Dictionary<string, long>? FunctionGas { get; init; }
    public long MemoryInitGas { get; init; }
    public long DataSectionGas { get; init; }
}

/// <summary>Contract analysis result.</summary>
public record ContractAnalysis
{
    public SizeBreakdown? SizeBreakdown { get; init; }
    public List<FunctionAnalysis>? Functions { get; init; }
    public List<ImportAnalysis>? Imports { get; init; }
    public SecurityAnalysis? Security { get; init; }
    public GasAnalysis? GasAnalysis { get; init; }
}

// ============================================================================
// Error Types
// ============================================================================

/// <summary>Compiler exception.</summary>
public class CompilerException : Exception
{
    public string? Code { get; }
    public int? HttpStatus { get; }

    public CompilerException(string message, string? code = null, int? httpStatus = null)
        : base(message)
    {
        Code = code;
        HttpStatus = httpStatus;
    }
}

// ============================================================================
// Constants
// ============================================================================

/// <summary>Compiler constants.</summary>
public static class CompilerConstants
{
    public const int MaxContractSize = 256 * 1024;
    public const int MaxMemoryPages = 16;
}
