package lib

import (
	"database/sql"
	"fmt"
)

// HexID is an int64 that marshals to/from 16-char hex in JSON.
type HexID int64

func (h HexID) MarshalJSON() ([]byte, error) {
	return []byte(`"` + IDToHex(int64(h)) + `"`), nil
}

func (h *HexID) UnmarshalJSON(data []byte) error {
	if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
		return fmt.Errorf("HexID must be a quoted string")
	}
	v, err := HexToID(string(data[1 : len(data)-1]))
	if err != nil {
		return err
	}
	*h = HexID(v)
	return nil
}

// VaultField represents a single field within a vault entry.
type VaultField struct {
	Label   string `json:"label"`
	Value   string `json:"value"`
	Kind    string `json:"kind"`              // text|password|totp|url|file
	Section string `json:"section,omitempty"`
	L2      bool   `json:"l2,omitempty"`      // legacy: true = L3 in new model
	Tier    int    `json:"tier,omitempty"`     // 1=L1, 2=L2 (agent), 3=L3 (hardware)
}

// VaultFile represents an attached file.
type VaultFile struct {
	Name     string `json:"name"`
	MimeType string `json:"mime_type"`
	Size     int64  `json:"size"`
	Data     []byte `json:"data"`
}

// VaultData is the JSON structure packed into Entry.Data.
type VaultData struct {
	Title          string       `json:"title"`
	Type           string       `json:"type"`
	Fields         []VaultField `json:"fields"`
	URLs           []string     `json:"urls,omitempty"`
	Expires        string       `json:"expires,omitempty"` // YYYY-MM-DD
	Notes          string       `json:"notes,omitempty"`
	Files          []VaultFile  `json:"files,omitempty"`
	SourceModified int64        `json:"source_modified,omitempty"` // Unix seconds from import source; 0 = unknown
}

// Entry is the core data model — single table for all vault items.
type Entry struct {
	EntryID   HexID  `json:"entry_id"`
	ParentID  HexID  `json:"parent_id"` // folder entry_id, or 0 for root
	Type      string `json:"type"`      // credential|note|identity|card|ssh_key|totp|folder|custom
	Title     string `json:"title"`     // plaintext for UI
	TitleIdx  []byte `json:"-"`         // HMAC-SHA256 blind index for search
	Data      []byte `json:"-"`         // packed: zstd + AES-256-GCM
	DataLevel int    `json:"data_level"` // 1=L1, 2=L2
	CreatedAt int64  `json:"created_at"`
	UpdatedAt int64  `json:"updated_at"`
	Version   int    `json:"version"` // optimistic locking
	DeletedAt *int64 `json:"deleted_at,omitempty"`
	Checksum  *int64 `json:"-"` // reserved for tamper detection

	// Unpacked field (not stored directly, populated after decrypt)
	VaultData *VaultData `json:"data,omitempty"`
}

// Session represents an authenticated session.
type Session struct {
	Token     string `json:"token"`
	CreatedAt int64  `json:"created_at"`
	ExpiresAt int64  `json:"expires_at"`
	Actor     string `json:"actor"` // web|extension|mcp
}

// AuditEvent represents a security audit log entry.
type AuditEvent struct {
	EventID   HexID  `json:"event_id"`
	EntryID   HexID  `json:"entry_id,omitempty"`
	Title     string `json:"title,omitempty"` // snapshot of entry title
	Action    string `json:"action"`          // read|fill|ai_read|create|update|delete|import|export
	Actor     string `json:"actor"`           // web|extension|mcp
	IPAddr    string `json:"ip_addr,omitempty"`
	CreatedAt int64  `json:"created_at"`
}

// MCPToken represents a scoped MCP access token.
type MCPToken struct {
	ID        HexID    `json:"id"`
	Label     string   `json:"label"`
	Token    string  `json:"token"`
	EntryIDs []HexID `json:"entry_ids,omitempty"`
	ReadOnly  bool     `json:"read_only"`
	ExpiresAt int64    `json:"expires_at"`
	LastUsed  int64    `json:"last_used"`
	CreatedAt int64    `json:"created_at"`
}

// WebAuthnCredential stores a registered WebAuthn credential.
type WebAuthnCredential struct {
	CredID       HexID  `json:"cred_id"`
	Name         string `json:"name"`
	PublicKey    []byte `json:"public_key"`
	CredentialID []byte `json:"credential_id"` // raw WebAuthn credential ID from authenticator
	PRFSalt      []byte `json:"prf_salt"`
	SignCount    int    `json:"sign_count"`
	CreatedAt    int64  `json:"created_at"`
}

// DB wraps the database connection.
type DB struct {
	Conn   *sql.DB
	DBPath string // filesystem path to the SQLite file
}

// Entry types
const (
	TypeCredential = "credential"
	TypeCard       = "card"
	TypeIdentity   = "identity"
	TypeNote       = "note"
	TypeSSHKey     = "ssh_key"
	TypeTOTP       = "totp"
	TypeFolder     = "folder"
	TypeCustom     = "custom"
)

// Data levels
const (
	DataLevelL1 = 1 // Server-side encrypted (AI-readable)
	DataLevelL2 = 2 // Client-side only (WebAuthn PRF)
)

// Actor types
const (
	ActorWeb       = "web"
	ActorExtension = "extension"
	ActorMCP       = "mcp"
	ActorAgent     = "agent"
)

// Action types
const (
	ActionRead         = "read"
	ActionFill         = "fill"
	ActionAIRead       = "ai_read"
	ActionCreate       = "create"
	ActionUpdate       = "update"
	ActionDelete       = "delete"
	ActionImport       = "import"
	ActionExport       = "export"
	ActionAgentCreate  = "agent_create"
	ActionAgentLock    = "agent_lock"
	ActionAgentUnlock  = "agent_unlock"
	ActionAgentRevoke  = "agent_revoke"
	ActionVaultLock    = "vault_lock"
	ActionVaultUnlock  = "vault_unlock"
	ActionIPViolation  = "ip_violation"
	ActionRateExceeded = "rate_exceeded"
)

// Agent status
const (
	AgentStatusActive  = "active"
	AgentStatusLocked  = "locked"
	AgentStatusRevoked = "revoked"
)

// Agent represents a registered CLI agent with rate limits and IP whitelist.
type Agent struct {
	ID              HexID    `json:"id"`
	Name            string   `json:"name"`
	IPWhitelist     []string `json:"ip_whitelist"`
	RateLimitMinute int      `json:"rate_limit_minute"`
	RateLimitHour   int      `json:"rate_limit_hour"`
	Status          string   `json:"status"`
	LockedReason    string   `json:"locked_reason,omitempty"`
	LockedAt        int64    `json:"locked_at,omitempty"`
	LastUsed        int64    `json:"last_used"`
	LastIP          string   `json:"last_ip,omitempty"`
	CreatedAt       int64    `json:"created_at"`
}

// VaultLock represents the vault-level lock state.
type VaultLock struct {
	Locked       bool   `json:"locked"`
	LockedReason string `json:"locked_reason,omitempty"`
	LockedAt     int64  `json:"locked_at,omitempty"`
}
