// Package ibc provides the Synor IBC SDK for Go.
//
// Inter-Blockchain Communication (IBC) protocol for cross-chain interoperability.
package ibc

import (
	"time"
)

// Height represents an IBC height
type Height struct {
	RevisionNumber uint64 `json:"revision_number"`
	RevisionHeight uint64 `json:"revision_height"`
}

// IsZero checks if height is zero
func (h Height) IsZero() bool {
	return h.RevisionNumber == 0 && h.RevisionHeight == 0
}

// Increment returns the next height
func (h Height) Increment() Height {
	return Height{RevisionNumber: h.RevisionNumber, RevisionHeight: h.RevisionHeight + 1}
}

// Timestamp in nanoseconds since Unix epoch
type Timestamp uint64

// Now returns current timestamp
func Now() Timestamp {
	return Timestamp(time.Now().UnixNano())
}

// ChainId represents a chain identifier
type ChainId struct {
	ID string `json:"id"`
}

// Version represents an IBC version
type Version struct {
	Identifier string   `json:"identifier"`
	Features   []string `json:"features"`
}

// DefaultConnectionVersion returns the default connection version
func DefaultConnectionVersion() Version {
	return Version{
		Identifier: "1",
		Features:   []string{"ORDER_ORDERED", "ORDER_UNORDERED"},
	}
}

// CommitmentPrefix for Merkle paths
type CommitmentPrefix struct {
	KeyPrefix []byte `json:"key_prefix"`
}

// ClientId represents a light client identifier
type ClientId struct {
	ID string `json:"id"`
}

// ClientType represents light client types
type ClientType string

const (
	ClientTypeTendermint  ClientType = "tendermint"
	ClientTypeSoloMachine ClientType = "solo-machine"
	ClientTypeLocalhost   ClientType = "localhost"
	ClientTypeWasm        ClientType = "wasm"
)

// TrustLevel configuration
type TrustLevel struct {
	Numerator   uint64 `json:"numerator"`
	Denominator uint64 `json:"denominator"`
}

// ClientState represents light client state
type ClientState struct {
	ChainID         string     `json:"chain_id"`
	TrustLevel      TrustLevel `json:"trust_level"`
	TrustingPeriod  uint64     `json:"trusting_period"`
	UnbondingPeriod uint64     `json:"unbonding_period"`
	MaxClockDrift   uint64     `json:"max_clock_drift"`
	LatestHeight    Height     `json:"latest_height"`
	FrozenHeight    *Height    `json:"frozen_height,omitempty"`
}

// ConsensusState at a specific height
type ConsensusState struct {
	Timestamp          Timestamp `json:"timestamp"`
	Root               []byte    `json:"root"`
	NextValidatorsHash []byte    `json:"next_validators_hash"`
}

// Validator info
type Validator struct {
	Address          []byte            `json:"address"`
	PubKey           map[string][]byte `json:"pub_key"`
	VotingPower      int64             `json:"voting_power"`
	ProposerPriority int64             `json:"proposer_priority"`
}

// ValidatorSet represents a set of validators
type ValidatorSet struct {
	Validators       []Validator `json:"validators"`
	Proposer         *Validator  `json:"proposer,omitempty"`
	TotalVotingPower int64       `json:"total_voting_power"`
}

// Header for light client updates
type Header struct {
	SignedHeader      map[string]interface{} `json:"signed_header"`
	ValidatorSet      ValidatorSet           `json:"validator_set"`
	TrustedHeight     Height                 `json:"trusted_height"`
	TrustedValidators ValidatorSet           `json:"trusted_validators"`
}

// ConnectionId represents a connection identifier
type ConnectionId struct {
	ID string `json:"id"`
}

// ConnectionState represents connection state
type ConnectionState string

const (
	ConnectionStateUninitialized ConnectionState = "uninitialized"
	ConnectionStateInit          ConnectionState = "init"
	ConnectionStateTryOpen       ConnectionState = "tryopen"
	ConnectionStateOpen          ConnectionState = "open"
)

// ConnectionCounterparty represents the counterparty
type ConnectionCounterparty struct {
	ClientID     ClientId          `json:"client_id"`
	ConnectionID *ConnectionId     `json:"connection_id,omitempty"`
	Prefix       *CommitmentPrefix `json:"prefix,omitempty"`
}

// ConnectionEnd represents a connection end
type ConnectionEnd struct {
	ClientID     ClientId               `json:"client_id"`
	Versions     []Version              `json:"versions"`
	State        ConnectionState        `json:"state"`
	Counterparty ConnectionCounterparty `json:"counterparty"`
	DelayPeriod  uint64                 `json:"delay_period"`
}

// PortId represents a port identifier
type PortId struct {
	ID string `json:"id"`
}

// TransferPort returns the transfer port
func TransferPort() PortId {
	return PortId{ID: "transfer"}
}

// ChannelId represents a channel identifier
type ChannelId struct {
	ID string `json:"id"`
}

// ChannelOrder represents channel ordering
type ChannelOrder string

const (
	ChannelOrderUnordered ChannelOrder = "unordered"
	ChannelOrderOrdered   ChannelOrder = "ordered"
)

// ChannelState represents channel state
type ChannelState string

const (
	ChannelStateUninitialized ChannelState = "uninitialized"
	ChannelStateInit          ChannelState = "init"
	ChannelStateTryOpen       ChannelState = "tryopen"
	ChannelStateOpen          ChannelState = "open"
	ChannelStateClosed        ChannelState = "closed"
)

// ChannelCounterparty represents the counterparty
type ChannelCounterparty struct {
	PortID    PortId     `json:"port_id"`
	ChannelID *ChannelId `json:"channel_id,omitempty"`
}

// Channel represents a channel end
type Channel struct {
	State          ChannelState        `json:"state"`
	Ordering       ChannelOrder        `json:"ordering"`
	Counterparty   ChannelCounterparty `json:"counterparty"`
	ConnectionHops []ConnectionId      `json:"connection_hops"`
	Version        string              `json:"version"`
}

// Packet represents an IBC packet
type Packet struct {
	Sequence         uint64    `json:"sequence"`
	SourcePort       PortId    `json:"source_port"`
	SourceChannel    ChannelId `json:"source_channel"`
	DestPort         PortId    `json:"dest_port"`
	DestChannel      ChannelId `json:"dest_channel"`
	Data             []byte    `json:"data"`
	TimeoutHeight    Height    `json:"timeout_height"`
	TimeoutTimestamp Timestamp `json:"timeout_timestamp"`
}

// PacketCommitment hash
type PacketCommitment struct {
	Hash []byte `json:"hash"`
}

// Acknowledgement represents packet acknowledgement
type Acknowledgement struct {
	Success *[]byte `json:"success,omitempty"`
	Error   *string `json:"error,omitempty"`
}

// IsSuccess checks if acknowledgement is success
func (a Acknowledgement) IsSuccess() bool {
	return a.Success != nil
}

// Timeout information
type Timeout struct {
	Height    Height    `json:"height"`
	Timestamp Timestamp `json:"timestamp"`
}

// HeightTimeout creates a height-only timeout
func HeightTimeout(height uint64) Timeout {
	return Timeout{Height: Height{RevisionHeight: height}}
}

// FungibleTokenPacketData for ICS-20 transfers
type FungibleTokenPacketData struct {
	Denom    string `json:"denom"`
	Amount   string `json:"amount"`
	Sender   string `json:"sender"`
	Receiver string `json:"receiver"`
	Memo     string `json:"memo,omitempty"`
}

// SwapId represents a swap identifier
type SwapId struct {
	ID string `json:"id"`
}

// SwapState represents swap state
type SwapState string

const (
	SwapStatePending   SwapState = "pending"
	SwapStateLocked    SwapState = "locked"
	SwapStateCompleted SwapState = "completed"
	SwapStateRefunded  SwapState = "refunded"
	SwapStateExpired   SwapState = "expired"
	SwapStateCancelled SwapState = "cancelled"
)

// SwapAsset types
type SwapAsset struct {
	Native *NativeAsset `json:"native,omitempty"`
	Ics20  *Ics20Asset  `json:"ics20,omitempty"`
	Ics721 *Ics721Asset `json:"ics721,omitempty"`
}

// NativeAsset represents native blockchain token
type NativeAsset struct {
	Amount uint64 `json:"amount"`
}

// Ics20Asset represents ICS-20 fungible token
type Ics20Asset struct {
	Denom  string `json:"denom"`
	Amount uint64 `json:"amount"`
}

// Ics721Asset represents ICS-721 NFT
type Ics721Asset struct {
	ClassID  string   `json:"class_id"`
	TokenIDs []string `json:"token_ids"`
}

// Hashlock - hash of the secret
type Hashlock struct {
	Hash []byte `json:"hash"`
}

// Timelock - expiration time
type Timelock struct {
	Expiry Timestamp `json:"expiry"`
}

// IsExpired checks if timelock has expired
func (t Timelock) IsExpired(current Timestamp) bool {
	return current >= t.Expiry
}

// Htlc represents a Hashed Time-Locked Contract
type Htlc struct {
	SwapID      SwapId     `json:"swap_id"`
	State       SwapState  `json:"state"`
	Initiator   string     `json:"initiator"`
	Responder   string     `json:"responder"`
	Asset       SwapAsset  `json:"asset"`
	Hashlock    Hashlock   `json:"hashlock"`
	Timelock    Timelock   `json:"timelock"`
	Secret      []byte     `json:"secret,omitempty"`
	ChannelID   *ChannelId `json:"channel_id,omitempty"`
	PortID      *PortId    `json:"port_id,omitempty"`
	CreatedAt   Timestamp  `json:"created_at"`
	CompletedAt *Timestamp `json:"completed_at,omitempty"`
}

// AtomicSwap between two chains
type AtomicSwap struct {
	SwapID        SwapId    `json:"swap_id"`
	InitiatorHtlc Htlc      `json:"initiator_htlc"`
	ResponderHtlc *Htlc     `json:"responder_htlc,omitempty"`
	State         SwapState `json:"state"`
}

// SwapAction represents swap packet actions
type SwapAction string

const (
	SwapActionInitiate SwapAction = "initiate"
	SwapActionRespond  SwapAction = "respond"
	SwapActionClaim    SwapAction = "claim"
	SwapActionRefund   SwapAction = "refund"
)

// SwapPacketData for cross-chain swaps
type SwapPacketData struct {
	SwapID         SwapId     `json:"swap_id"`
	Action         SwapAction `json:"action"`
	Initiator      string     `json:"initiator"`
	Responder      string     `json:"responder"`
	Asset          SwapAsset  `json:"asset"`
	Hashlock       Hashlock   `json:"hashlock"`
	TimelockExpiry uint64     `json:"timelock_expiry"`
	Secret         []byte     `json:"secret,omitempty"`
}

// MerkleProof for commitment verification
type MerkleProof struct {
	Proofs []ProofOp `json:"proofs"`
}

// ProofOp represents a proof operation
type ProofOp struct {
	Type string `json:"type"`
	Key  []byte `json:"key"`
	Data []byte `json:"data"`
}

// CommitmentProof with height
type CommitmentProof struct {
	Proof  MerkleProof `json:"proof"`
	Height Height      `json:"height"`
}

// IbcEvent represents IBC events
type IbcEvent struct {
	Type string                 `json:"type"`
	Data map[string]interface{} `json:"data"`
}

// Config for IBC SDK
type Config struct {
	APIKey     string
	Endpoint   string
	WSEndpoint string
	Timeout    time.Duration
	Retries    int
	ChainID    string
	Debug      bool
}

// DefaultConfig returns default configuration
func DefaultConfig(apiKey string) Config {
	return Config{
		APIKey:     apiKey,
		Endpoint:   "https://ibc.synor.io/v1",
		WSEndpoint: "wss://ibc.synor.io/v1/ws",
		Timeout:    30 * time.Second,
		Retries:    3,
		ChainID:    "synor-1",
		Debug:      false,
	}
}

// IbcError represents IBC errors
type IbcError struct {
	Message string
	Code    string
	Status  int
}

func (e *IbcError) Error() string {
	return e.Message
}
