package db

import (
	"context"
	"time"

	"github.com/dtoro/oikos/internal/core/ports"
	"github.com/google/uuid"
)

// KnowledgeRepo implements ports.KnowledgeRepository.
type KnowledgeRepo struct {
	pool *Pool
}

var _ ports.KnowledgeRepository = (*KnowledgeRepo)(nil)

func NewKnowledgeRepo(pool *Pool) *KnowledgeRepo { return &KnowledgeRepo{pool: pool} }

func (r *KnowledgeRepo) Search(ctx context.Context, query string, limit int) ([]ports.KnowledgeEntry, error) {
	rows, err := r.pool.Query(ctx, `
		SELECT k.slug, k.title, k.kind, k.updated_at
		FROM knowledge_entities k
		WHERE k.deleted_at IS NULL
		  AND (k.slug ILIKE '%'||$1||'%' OR k.title ILIKE '%'||$1||'%' OR k.content ILIKE '%'||$1||'%')
		ORDER BY k.updated_at DESC LIMIT $2`, query, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []ports.KnowledgeEntry
	for rows.Next() {
		entry, err := scanKnowledgeEntry(rows)
		if err != nil {
			return nil, err
		}
		items = append(items, entry)
	}
	return items, rows.Err()
}

func (r *KnowledgeRepo) GetContent(ctx context.Context, slug string) (ports.KnowledgeEntry, error) {
	return scanKnowledgeEntry(r.pool.QueryRow(ctx, `
		SELECT slug, title, kind, content, updated_at
		FROM knowledge_entities WHERE slug = $1 AND deleted_at IS NULL`, slug))
}

func (r *KnowledgeRepo) Upsert(ctx context.Context, input ports.KnowledgeUpsertInput) (ports.KnowledgeEntry, error) {
	id, _ := uuid.NewV7()
	_, err := r.pool.Exec(ctx, `
		INSERT INTO knowledge_entities (slug, title, kind, content, updated_at)
		VALUES ($1, $2, $3, $4, now())
		ON CONFLICT (slug) DO UPDATE
		SET title = $2, kind = $3, content = $4, updated_at = now()`,
		input.Entry.Slug, input.Entry.Title, input.Entry.Kind, input.Entry.Content)
	if err != nil {
		return ports.KnowledgeEntry{}, err
	}
	_ = id
	return input.Entry, nil
}

func (r *KnowledgeRepo) Tags(ctx context.Context) (map[string]int, error) {
	return nil, nil
}

func (r *KnowledgeRepo) SoftDelete(ctx context.Context, slug string) error {
	_, err := r.pool.Exec(ctx, `UPDATE knowledge_entities SET deleted_at = now() WHERE slug = $1`, slug)
	return err
}

func (r *KnowledgeRepo) Restore(ctx context.Context, slug string) error {
	_, err := r.pool.Exec(ctx, `UPDATE knowledge_entities SET deleted_at = NULL WHERE slug = $1`, slug)
	return err
}

func (r *KnowledgeRepo) Revisions(ctx context.Context, slug string, limit int) ([]ports.KnowledgeEntry, error) {
	return nil, nil
}

func (r *KnowledgeRepo) Orphans(ctx context.Context, staleDays int) ([]ports.KnowledgeEntry, error) {
	return nil, nil
}

func (r *KnowledgeRepo) Duplicates(ctx context.Context, threshold float64) ([]ports.KnowledgeEntry, error) {
	return nil, nil
}

func (r *KnowledgeRepo) Merge(ctx context.Context, targetSlug string, sourceSlugs []string) error {
	return nil
}

func scanKnowledgeEntry(row interface{ Scan(dest ...any) error }) (ports.KnowledgeEntry, error) {
	var slug, title, kind, content string
	var updatedAt time.Time
	if err := row.Scan(&slug, &title, &kind, &content, &updatedAt); err != nil {
		return ports.KnowledgeEntry{}, err
	}
	return ports.KnowledgeEntry{
		Slug: slug, Title: title, Kind: kind, Content: content, UpdatedAt: updatedAt,
	}, nil
}