package training

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/google/uuid"
)

// LogAction creates an audit log entry
func (s *Store) LogAction(ctx context.Context, entry *AuditLogEntry) error {
	entry.ID = uuid.New()
	entry.CreatedAt = time.Now().UTC()

	details, _ := json.Marshal(entry.Details)

	_, err := s.pool.Exec(ctx, `
		INSERT INTO training_audit_log (
			id, tenant_id, user_id, action, entity_type,
			entity_id, details, ip_address, created_at
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
	`,
		entry.ID, entry.TenantID, entry.UserID, string(entry.Action), string(entry.EntityType),
		entry.EntityID, details, entry.IPAddress, entry.CreatedAt,
	)

	return err
}

// ListAuditLog lists audit log entries for a tenant
func (s *Store) ListAuditLog(ctx context.Context, tenantID uuid.UUID, filters *AuditLogFilters) ([]AuditLogEntry, int, error) {
	countQuery := "SELECT COUNT(*) FROM training_audit_log WHERE tenant_id = $1"
	countArgs := []interface{}{tenantID}
	countArgIdx := 2

	query := `
		SELECT
			id, tenant_id, user_id, action, entity_type,
			entity_id, details, ip_address, created_at
		FROM training_audit_log WHERE tenant_id = $1`

	args := []interface{}{tenantID}
	argIdx := 2

	if filters != nil {
		if filters.UserID != nil {
			query += fmt.Sprintf(" AND user_id = $%d", argIdx)
			args = append(args, *filters.UserID)
			argIdx++
			countQuery += fmt.Sprintf(" AND user_id = $%d", countArgIdx)
			countArgs = append(countArgs, *filters.UserID)
			countArgIdx++
		}
		if filters.Action != "" {
			query += fmt.Sprintf(" AND action = $%d", argIdx)
			args = append(args, string(filters.Action))
			argIdx++
			countQuery += fmt.Sprintf(" AND action = $%d", countArgIdx)
			countArgs = append(countArgs, string(filters.Action))
			countArgIdx++
		}
		if filters.EntityType != "" {
			query += fmt.Sprintf(" AND entity_type = $%d", argIdx)
			args = append(args, string(filters.EntityType))
			argIdx++
			countQuery += fmt.Sprintf(" AND entity_type = $%d", countArgIdx)
			countArgs = append(countArgs, string(filters.EntityType))
			countArgIdx++
		}
	}

	var total int
	err := s.pool.QueryRow(ctx, countQuery, countArgs...).Scan(&total)
	if err != nil {
		return nil, 0, err
	}

	query += " ORDER BY created_at DESC"

	if filters != nil && filters.Limit > 0 {
		query += fmt.Sprintf(" LIMIT $%d", argIdx)
		args = append(args, filters.Limit)
		argIdx++
		if filters.Offset > 0 {
			query += fmt.Sprintf(" OFFSET $%d", argIdx)
			args = append(args, filters.Offset)
			argIdx++
		}
	}

	rows, err := s.pool.Query(ctx, query, args...)
	if err != nil {
		return nil, 0, err
	}
	defer rows.Close()

	var entries []AuditLogEntry
	for rows.Next() {
		var entry AuditLogEntry
		var action, entityType string
		var details []byte

		err := rows.Scan(
			&entry.ID, &entry.TenantID, &entry.UserID, &action, &entityType,
			&entry.EntityID, &details, &entry.IPAddress, &entry.CreatedAt,
		)
		if err != nil {
			return nil, 0, err
		}

		entry.Action = AuditAction(action)
		entry.EntityType = AuditEntityType(entityType)
		json.Unmarshal(details, &entry.Details)
		if entry.Details == nil {
			entry.Details = map[string]interface{}{}
		}

		entries = append(entries, entry)
	}

	if entries == nil {
		entries = []AuditLogEntry{}
	}

	return entries, total, nil
}
