package db

import (
	"context"
	"database/sql"

	"github.com/bluesky-social/indigo/atproto/syntax"
	"tangled.org/core/orm"
)

type KnotMember struct {
	Id      int
	Did     syntax.DID
	Subject syntax.DID
	Created string
}

func (d *DB) IsMigrationApplied(name string) (bool, error) {
	var exists bool
	err := d.db.QueryRow(
		`select exists (select 1 from migrations where name = ?)`,
		name,
	).Scan(&exists)
	return exists, err
}

func (d *DB) ApplyKnotMemberBackfill(ctx context.Context, rows []KnotMember, migrationName string) error {
	conn, err := d.db.Conn(ctx)
	if err != nil {
		return err
	}
	defer conn.Close()

	return orm.RunMigration(conn, d.logger, migrationName, func(tx *sql.Tx) error {
		for _, m := range rows {
			if err := AddDid(tx, m.Subject.String()); err != nil {
				return err
			}
			if err := AddKnotMemberDirect(tx, m.Did, m.Subject); err != nil {
				return err
			}
		}
		return nil
	})
}

func AddKnotMemberDirect(q DBTX, addedBy, subject syntax.DID) error {
	_, err := q.Exec(
		`insert or ignore into knot_members (did, rkey, subject) values (?, NULL, ?)`,
		addedBy,
		subject,
	)
	return err
}

func RemoveKnotMemberBySubject(q DBTX, subject syntax.DID) error {
	_, err := q.Exec(
		"delete from knot_members where subject = ?",
		subject,
	)
	return err
}

func RemoveKnotMemberDirect(q DBTX, subject syntax.DID) error {
	_, err := q.Exec(
		"delete from knot_members where subject = ? and rkey is null",
		subject,
	)
	return err
}

func CountKnotMembersBySubject(q DBTX, subject string) (int, error) {
	var count int
	err := q.QueryRow(
		`select count(*) from knot_members where subject = ?`,
		subject,
	).Scan(&count)
	return count, err
}

func ListKnotMembers(q DBTX, p ListPage) ([]KnotMember, *int, error) {
	return listPaged(q,
		`select id, did, subject, created
		from knot_members
		where id in (select min(id) from knot_members group by subject)`,
		nil, p,
		func(r *sql.Rows) (KnotMember, error) {
			var m KnotMember
			err := r.Scan(&m.Id, &m.Did, &m.Subject, &m.Created)
			return m, err
		},
		func(m KnotMember) int { return m.Id },
	)
}
