package store

import (
	"encoding/json"
	"strings"
	"time"

	"quantex.com/qfixpt/src/common/tracerr"
	"quantex.com/qfixpt/src/domain"
)

func (p *Store) SaveMessage(msg domain.TradeMessage) error {
	jsonBytes, err := json.Marshal(msg.JMessage)
	if err != nil {
		return tracerr.Errorf("error marshaling j_message: %w", err)
	}

	_, err = p.db.Exec(
		"INSERT INTO qfixpt_messages (trade_id, j_message) VALUES ($1, $2)",
		msg.TradeID, string(jsonBytes),
	)
	if err != nil {
		return tracerr.Errorf("error inserting message: %w", err)
	}

	return nil
}

func (p *Store) SaveLog(entry domain.LogEntry) error {
	upsertStmt := `INSERT INTO qfixpt_logs (trade_id, raw_msg)
		VALUES ($1, $2)
		ON CONFLICT (trade_id) DO UPDATE
		SET raw_msg = qfixpt_logs.raw_msg || E'\n' || EXCLUDED.raw_msg,
		    updated_at = NOW()`

	_, err := p.db.Exec(upsertStmt, entry.TradeID, entry.RawMsg)
	if err != nil {
		return tracerr.Errorf("error upserting log: %w", err)
	}

	return nil
}

func (p *Store) GetTodayMessages() ([]domain.TradeMessage, error) {
	rows, err := p.db.Query(
		"SELECT id, trade_id, j_message, created_at FROM qfixpt_messages WHERE created_at >= current_date ORDER BY created_at ASC",
	)
	if err != nil {
		return nil, tracerr.Errorf("error querying today messages: %w", err)
	}
	defer rows.Close()

	var messages []domain.TradeMessage

	for rows.Next() {
		var (
			id, tradeID string
			jMessageRaw []byte
			createdAt   time.Time
		)

		if err := rows.Scan(&id, &tradeID, &jMessageRaw, &createdAt); err != nil {
			return nil, tracerr.Errorf("error scanning message row: %w", err)
		}

		var jMessage domain.FixMessageJSON
		if err := json.Unmarshal(jMessageRaw, &jMessage); err != nil {
			return nil, tracerr.Errorf("error unmarshaling j_message: %w", err)
		}

		messages = append(messages, domain.TradeMessage{
			ID:        id,
			TradeID:   tradeID,
			JMessage:  jMessage,
			CreatedAt: createdAt,
		})
	}

	if err := rows.Err(); err != nil {
		return nil, tracerr.Errorf("error iterating message rows: %w", err)
	}

	return messages, nil
}

func (p *Store) GetLogsByTradeID(tradeID string) (domain.Logs, error) {
	rows, err := p.db.Query("SELECT raw_msg FROM qfixpt_logs WHERE trade_id = $1", tradeID)
	if err != nil {
		return domain.Logs{}, tracerr.Errorf("error querying logs: %w", err)
	}
	defer rows.Close()

	if !rows.Next() {
		return domain.Logs{}, nil
	}

	var rawMsg string
	if err := rows.Scan(&rawMsg); err != nil {
		return domain.Logs{}, tracerr.Errorf("error scanning log row: %w", err)
	}

	return domain.Logs{Entries: strings.Split(rawMsg, "\n")}, nil
}
