package sqlite

import (
	"context"
	"database/sql"
	"time"

	"chat-switchboard/models"
	"chat-switchboard/store"
)

// ── SessionStore ───────────────────────────

type SessionStore struct{}

func NewSessionStore() *SessionStore { return &SessionStore{} }

func (s *SessionStore) Create(ctx context.Context, sp *models.SessionParticipant) error {
	if sp.ID == "" {
		sp.ID = store.NewID()
	}
	_, err := DB.ExecContext(ctx, `
		INSERT INTO session_participants (id, session_token, channel_id, display_name, fingerprint)
		VALUES (?, ?, ?, ?, ?)`,
		sp.ID, sp.SessionToken, sp.ChannelID, sp.DisplayName, nullText(sp.Fingerprint),
	)
	if err != nil {
		return err
	}
	return DB.QueryRowContext(ctx, `SELECT created_at FROM session_participants WHERE id = ?`, sp.ID).
		Scan(st(&sp.CreatedAt))
}

func (s *SessionStore) GetByToken(ctx context.Context, token string) (*models.SessionParticipant, error) {
	sp := &models.SessionParticipant{}
	err := DB.QueryRowContext(ctx, `
		SELECT id, session_token, channel_id, display_name, COALESCE(fingerprint, ''), created_at
		FROM session_participants WHERE session_token = ?`, token,
	).Scan(&sp.ID, &sp.SessionToken, &sp.ChannelID, &sp.DisplayName, &sp.Fingerprint, st(&sp.CreatedAt))
	if err != nil {
		return nil, err
	}
	return sp, nil
}

func (s *SessionStore) GetByID(ctx context.Context, id string) (*models.SessionParticipant, error) {
	sp := &models.SessionParticipant{}
	err := DB.QueryRowContext(ctx, `
		SELECT id, session_token, channel_id, display_name, COALESCE(fingerprint, ''), created_at
		FROM session_participants WHERE id = ?`, id,
	).Scan(&sp.ID, &sp.SessionToken, &sp.ChannelID, &sp.DisplayName, &sp.Fingerprint, st(&sp.CreatedAt))
	if err != nil {
		return nil, err
	}
	return sp, nil
}

func (s *SessionStore) ListForChannel(ctx context.Context, channelID string) ([]models.SessionParticipant, error) {
	rows, err := DB.QueryContext(ctx, `
		SELECT id, session_token, channel_id, display_name, COALESCE(fingerprint, ''), created_at
		FROM session_participants WHERE channel_id = ?
		ORDER BY created_at ASC`, channelID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var result []models.SessionParticipant
	for rows.Next() {
		var sp models.SessionParticipant
		if err := rows.Scan(&sp.ID, &sp.SessionToken, &sp.ChannelID, &sp.DisplayName, &sp.Fingerprint, st(&sp.CreatedAt)); err != nil {
			return nil, err
		}
		result = append(result, sp)
	}
	return result, rows.Err()
}

func (s *SessionStore) CountForChannel(ctx context.Context, channelID string) (int, error) {
	var count int
	err := DB.QueryRowContext(ctx, `
		SELECT COUNT(*) FROM session_participants WHERE channel_id = ?`, channelID,
	).Scan(&count)
	return count, err
}

func (s *SessionStore) Delete(ctx context.Context, id string) error {
	res, err := DB.ExecContext(ctx, `DELETE FROM session_participants WHERE id = ?`, id)
	if err != nil {
		return err
	}
	n, _ := res.RowsAffected()
	if n == 0 {
		return sql.ErrNoRows
	}
	return nil
}

// DeleteExpired removes sessions created before olderThan whose channel
// has no messages. Returns the count of deleted rows.
func (s *SessionStore) DeleteExpired(ctx context.Context, olderThan time.Time) (int64, error) {
	res, err := DB.ExecContext(ctx, `
		DELETE FROM session_participants
		WHERE created_at < ?
		AND NOT EXISTS (
			SELECT 1 FROM messages WHERE messages.channel_id = session_participants.channel_id
		)`, olderThan)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func nullText(s string) interface{} {
	if s == "" {
		return nil
	}
	return s
}
