package audit

import (
	"context"
	"crypto/sha256"
	"database/sql"
	"encoding/hex"
	"encoding/json"
	"log"
	"time"

	"github.com/google/uuid"
)

type Event struct {
	ID           string
	Timestamp    time.Time
	UserID       string
	Action       string
	ResourceType string
	ResourceID   string
	Success      bool
	Details      map[string]any
	// Enhanced fields
	Actor       string // Username or user identifier
	Resource    string // Full resource identifier (e.g., "pool:my-pool")
	PayloadHash string // SHA256 hash of request payload
	Result      string // Success/failure message or status
	ClientIP    string // Client IP address
}

type AuditLogger interface {
	Record(ctx context.Context, e Event) error
}

type SQLAuditLogger struct {
	DB *sql.DB
}

func NewSQLAuditLogger(db *sql.DB) *SQLAuditLogger {
	return &SQLAuditLogger{DB: db}
}

func (l *SQLAuditLogger) Record(ctx context.Context, e Event) error {
	if e.ID == "" {
		e.ID = uuid.New().String()
	}
	if e.Timestamp.IsZero() {
		e.Timestamp = time.Now()
	}

	// Set actor from UserID if not provided
	if e.Actor == "" {
		e.Actor = e.UserID
	}

	// Build resource string from ResourceType and ResourceID
	if e.Resource == "" {
		if e.ResourceID != "" {
			e.Resource = e.ResourceType + ":" + e.ResourceID
		} else {
			e.Resource = e.ResourceType
		}
	}

	// Set result from Success if not provided
	if e.Result == "" {
		if e.Success {
			e.Result = "success"
		} else {
			e.Result = "failure"
		}
	}

	detailsJSON, _ := json.Marshal(e.Details)

	// Try to insert with all columns, fallback to basic columns if enhanced columns don't exist
	_, err := l.DB.ExecContext(ctx,
		`INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details, actor, resource, payload_hash, result, client_ip) 
		 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
		e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON),
		e.Actor, e.Resource, e.PayloadHash, e.Result, e.ClientIP)
	if err != nil {
		// Fallback to basic insert if enhanced columns don't exist yet
		_, err2 := l.DB.ExecContext(ctx,
			`INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details) 
			 VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
			e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON))
		if err2 != nil {
			log.Printf("audit record failed: %v (fallback also failed: %v)", err, err2)
			return err2
		}
		log.Printf("audit record inserted with fallback (enhanced columns may not exist): %v", err)
	}
	return nil
}

// HashPayload computes SHA256 hash of a payload (JSON string or bytes)
func HashPayload(payload interface{}) string {
	var data []byte
	switch v := payload.(type) {
	case []byte:
		data = v
	case string:
		data = []byte(v)
	default:
		jsonData, _ := json.Marshal(payload)
		data = jsonData
	}
	hash := sha256.Sum256(data)
	return hex.EncodeToString(hash[:])
}

func boolToInt(b bool) int {
	if b {
		return 1
	}
	return 0
}
