// Package compiler provides the Synor Compiler SDK for Go.
//
// Smart contract compilation, optimization, and ABI generation.
package compiler

import (
	"encoding/json"
	"fmt"
)

// OptimizationLevel represents the optimization level for WASM compilation.
type OptimizationLevel string

const (
	OptimizationNone       OptimizationLevel = "none"
	OptimizationBasic      OptimizationLevel = "basic"
	OptimizationSize       OptimizationLevel = "size"
	OptimizationAggressive OptimizationLevel = "aggressive"
)

// StripOptions defines options for stripping WASM sections.
type StripOptions struct {
	StripDebug       bool     `json:"strip_debug"`
	StripProducers   bool     `json:"strip_producers"`
	StripNames       bool     `json:"strip_names"`
	StripCustom      bool     `json:"strip_custom"`
	PreserveSections []string `json:"preserve_sections"`
	StripUnused      bool     `json:"strip_unused"`
}

// DefaultStripOptions returns the default strip options.
func DefaultStripOptions() StripOptions {
	return StripOptions{
		StripDebug:       true,
		StripProducers:   true,
		StripNames:       true,
		StripCustom:      true,
		PreserveSections: []string{},
		StripUnused:      true,
	}
}

// CompilerConfig holds the configuration for the compiler client.
type CompilerConfig struct {
	APIKey            string            `json:"api_key"`
	Endpoint          string            `json:"endpoint"`
	Timeout           int               `json:"timeout"` // milliseconds
	Retries           int               `json:"retries"`
	Debug             bool              `json:"debug"`
	OptimizationLevel OptimizationLevel `json:"optimization_level"`
	StripOptions      *StripOptions     `json:"strip_options,omitempty"`
	MaxContractSize   int               `json:"max_contract_size"`
	UseWasmOpt        bool              `json:"use_wasm_opt"`
	Validate          bool              `json:"validate"`
	ExtractMetadata   bool              `json:"extract_metadata"`
	GenerateAbi       bool              `json:"generate_abi"`
}

// DefaultConfig returns a default configuration.
func DefaultConfig(apiKey string) CompilerConfig {
	return CompilerConfig{
		APIKey:            apiKey,
		Endpoint:          "https://compiler.synor.io/v1",
		Timeout:           60000,
		Retries:           3,
		Debug:             false,
		OptimizationLevel: OptimizationSize,
		StripOptions:      nil,
		MaxContractSize:   256 * 1024,
		UseWasmOpt:        true,
		Validate:          true,
		ExtractMetadata:   true,
		GenerateAbi:       true,
	}
}

// CompilationRequest represents a compilation request.
type CompilationRequest struct {
	Wasm              string             `json:"wasm"` // Base64 encoded
	OptimizationLevel *OptimizationLevel `json:"optimization_level,omitempty"`
	StripOptions      *StripOptions      `json:"strip_options,omitempty"`
	UseWasmOpt        *bool              `json:"use_wasm_opt,omitempty"`
	Validate          *bool              `json:"validate,omitempty"`
	ExtractMetadata   *bool              `json:"extract_metadata,omitempty"`
	GenerateAbi       *bool              `json:"generate_abi,omitempty"`
}

// ValidationError represents a validation error.
type ValidationError struct {
	Code     string  `json:"code"`
	Message  string  `json:"message"`
	Location *string `json:"location,omitempty"`
}

// ValidationResult represents the result of validation.
type ValidationResult struct {
	Valid         bool              `json:"valid"`
	Errors        []ValidationError `json:"errors"`
	Warnings      []string          `json:"warnings"`
	ExportCount   int               `json:"export_count"`
	ImportCount   int               `json:"import_count"`
	FunctionCount int               `json:"function_count"`
	MemoryPages   [2]*int           `json:"memory_pages"` // [min, max]
}

// ContractMetadata represents contract metadata.
type ContractMetadata struct {
	Name           *string           `json:"name,omitempty"`
	Version        *string           `json:"version,omitempty"`
	Authors        []string          `json:"authors"`
	Description    *string           `json:"description,omitempty"`
	License        *string           `json:"license,omitempty"`
	Repository     *string           `json:"repository,omitempty"`
	BuildTimestamp *int64            `json:"build_timestamp,omitempty"`
	RustVersion    *string           `json:"rust_version,omitempty"`
	SdkVersion     *string           `json:"sdk_version,omitempty"`
	Custom         map[string]string `json:"custom"`
}

// TypeInfo represents type information.
type TypeInfo struct {
	Kind     string      `json:"kind"`
	Size     *int        `json:"size,omitempty"`
	Element  *TypeInfo   `json:"element,omitempty"`
	Inner    *TypeInfo   `json:"inner,omitempty"`
	Elements []TypeInfo  `json:"elements,omitempty"`
	Name     *string     `json:"name,omitempty"`
	Fields   []TypeField `json:"fields,omitempty"`
}

// TypeField represents a struct field.
type TypeField struct {
	Name string   `json:"name"`
	Type TypeInfo `json:"type"`
}

// TypeName returns the type name as a string.
func (t TypeInfo) TypeName() string {
	switch t.Kind {
	case "u8", "u16", "u32", "u64", "u128", "i8", "i16", "i32", "i64", "i128",
		"bool", "string", "bytes", "address", "hash256":
		return t.Kind
	case "fixedBytes":
		if t.Size != nil {
			return fmt.Sprintf("bytes%d", *t.Size)
		}
		return "bytes"
	case "array":
		if t.Element != nil {
			return t.Element.TypeName() + "[]"
		}
		return "[]"
	case "fixedArray":
		if t.Element != nil && t.Size != nil {
			return fmt.Sprintf("%s[%d]", t.Element.TypeName(), *t.Size)
		}
		return "[]"
	case "option":
		if t.Inner != nil {
			return t.Inner.TypeName() + "?"
		}
		return "?"
	case "tuple":
		names := make([]string, len(t.Elements))
		for i, e := range t.Elements {
			names[i] = e.TypeName()
		}
		return "(" + join(names, ", ") + ")"
	case "struct":
		if t.Name != nil {
			return *t.Name
		}
		return "struct"
	default:
		if t.Name != nil {
			return *t.Name
		}
		return "unknown"
	}
}

func join(strs []string, sep string) string {
	if len(strs) == 0 {
		return ""
	}
	result := strs[0]
	for i := 1; i < len(strs); i++ {
		result += sep + strs[i]
	}
	return result
}

// ParamAbi represents a parameter ABI.
type ParamAbi struct {
	Name    string   `json:"name"`
	Type    TypeInfo `json:"type"`
	Indexed bool     `json:"indexed"`
}

// FunctionAbi represents a function ABI.
type FunctionAbi struct {
	Name     string     `json:"name"`
	Selector string     `json:"selector"`
	Inputs   []ParamAbi `json:"inputs"`
	Outputs  []ParamAbi `json:"outputs"`
	View     bool       `json:"view"`
	Payable  bool       `json:"payable"`
	Doc      *string    `json:"doc,omitempty"`
}

// EventAbi represents an event ABI.
type EventAbi struct {
	Name   string     `json:"name"`
	Topic  string     `json:"topic"`
	Params []ParamAbi `json:"params"`
	Doc    *string    `json:"doc,omitempty"`
}

// ErrorAbi represents an error ABI.
type ErrorAbi struct {
	Name     string     `json:"name"`
	Selector string     `json:"selector"`
	Params   []ParamAbi `json:"params"`
	Doc      *string    `json:"doc,omitempty"`
}

// ContractAbi represents the contract ABI.
type ContractAbi struct {
	Name      string        `json:"name"`
	Version   string        `json:"version"`
	Functions []FunctionAbi `json:"functions"`
	Events    []EventAbi    `json:"events"`
	Errors    []ErrorAbi    `json:"errors"`
}

// FindFunction finds a function by name.
func (a *ContractAbi) FindFunction(name string) *FunctionAbi {
	for i := range a.Functions {
		if a.Functions[i].Name == name {
			return &a.Functions[i]
		}
	}
	return nil
}

// FindBySelector finds a function by selector.
func (a *ContractAbi) FindBySelector(selector string) *FunctionAbi {
	for i := range a.Functions {
		if a.Functions[i].Selector == selector {
			return &a.Functions[i]
		}
	}
	return nil
}

// ToJSON serializes the ABI to JSON.
func (a *ContractAbi) ToJSON() (string, error) {
	data, err := json.MarshalIndent(a, "", "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// CompilationResult represents the result of compilation.
type CompilationResult struct {
	ContractID         string            `json:"contract_id"`
	Code               string            `json:"code"` // Base64 encoded
	CodeHash           string            `json:"code_hash"`
	OriginalSize       int               `json:"original_size"`
	OptimizedSize      int               `json:"optimized_size"`
	SizeReduction      float64           `json:"size_reduction"`
	Metadata           *ContractMetadata `json:"metadata,omitempty"`
	Abi                *ContractAbi      `json:"abi,omitempty"`
	EstimatedDeployGas int64             `json:"estimated_deploy_gas"`
	Validation         *ValidationResult `json:"validation,omitempty"`
	Warnings           []string          `json:"warnings"`
}

// SizeStats returns size statistics as a formatted string.
func (r *CompilationResult) SizeStats() string {
	return fmt.Sprintf("Original: %d bytes, Optimized: %d bytes, Reduction: %.1f%%",
		r.OriginalSize, r.OptimizedSize, r.SizeReduction)
}

// SourceMapping represents a source mapping entry.
type SourceMapping struct {
	WasmOffset int     `json:"wasm_offset"`
	Line       int     `json:"line"`
	Column     int     `json:"column"`
	Function   *string `json:"function,omitempty"`
}

// SourceMap represents a source map.
type SourceMap struct {
	File     string          `json:"file"`
	Mappings []SourceMapping `json:"mappings"`
}

// SizeBreakdown represents size breakdown.
type SizeBreakdown struct {
	Code      int `json:"code"`
	Data      int `json:"data"`
	Types     int `json:"types"`
	Functions int `json:"functions"`
	Memory    int `json:"memory"`
	Table     int `json:"table"`
	Exports   int `json:"exports"`
	Imports   int `json:"imports"`
	Custom    int `json:"custom"`
	Total     int `json:"total"`
}

// FunctionAnalysis represents function analysis.
type FunctionAnalysis struct {
	Name             string `json:"name"`
	Size             int    `json:"size"`
	InstructionCount int    `json:"instruction_count"`
	LocalCount       int    `json:"local_count"`
	Exported         bool   `json:"exported"`
	EstimatedGas     int64  `json:"estimated_gas"`
}

// ImportAnalysis represents import analysis.
type ImportAnalysis struct {
	Module    string  `json:"module"`
	Name      string  `json:"name"`
	Kind      string  `json:"kind"` // function, memory, table, global
	Signature *string `json:"signature,omitempty"`
}

// SecurityIssue represents a security issue.
type SecurityIssue struct {
	Severity    string  `json:"severity"` // low, medium, high, critical
	Type        string  `json:"type"`
	Description string  `json:"description"`
	Location    *string `json:"location,omitempty"`
}

// SecurityAnalysis represents security analysis.
type SecurityAnalysis struct {
	Score           int             `json:"score"` // 0-100
	Issues          []SecurityIssue `json:"issues"`
	Recommendations []string        `json:"recommendations"`
}

// GasAnalysis represents gas analysis.
type GasAnalysis struct {
	DeploymentGas  int64          `json:"deployment_gas"`
	FunctionGas    map[string]int `json:"function_gas"`
	MemoryInitGas  int64          `json:"memory_init_gas"`
	DataSectionGas int64          `json:"data_section_gas"`
}

// ContractAnalysis represents contract analysis result.
type ContractAnalysis struct {
	SizeBreakdown SizeBreakdown      `json:"size_breakdown"`
	Functions     []FunctionAnalysis `json:"functions"`
	Imports       []ImportAnalysis   `json:"imports"`
	Security      *SecurityAnalysis  `json:"security,omitempty"`
	GasAnalysis   *GasAnalysis       `json:"gas_analysis,omitempty"`
}

// CompilerError represents a compiler error.
type CompilerError struct {
	Message    string
	Code       string
	HTTPStatus int
}

func (e *CompilerError) Error() string {
	if e.Code != "" {
		return fmt.Sprintf("%s (%s)", e.Message, e.Code)
	}
	return e.Message
}

// Constants
const (
	MaxContractSize = 256 * 1024 // 256 KB
	MaxMemoryPages  = 16
)
