package store

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

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

func (p *Store) SaveMessage(msg domain.Message) 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 qfixdpl_messages (id, sender_comp_id, msg_seq_num, j_message, created_at)
		 VALUES ($1, $2, $3, $4, $5)`,
		msg.ID,
		msg.SenderCompID,
		strconv.Itoa(msg.MsgSeqNum),
		string(jsonBytes),
		msg.CreatedAt.UTC().Format(time.RFC3339Nano),
	)
	if err != nil {
		return tracerr.Errorf("error inserting message: %w", err)
	}

	return nil
}

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

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

	return nil
}

func (p *Store) GetTodayMessages() ([]domain.Message, error) {
	rows, err := p.db.Query(
		`SELECT id, sender_comp_id, msg_seq_num, j_message, created_at
		 FROM qfixdpl_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.Message

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

		if err := rows.Scan(&id, &senderCompID, &msgSeqNum, &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)
		}

		sendingTime, _ := jMessage.Header["SendingTime"].(time.Time)
		if sendingTime.IsZero() {
			if s, ok := jMessage.Header["SendingTime"].(string); ok {
				if t, parseErr := time.Parse(time.RFC3339Nano, s); parseErr == nil {
					sendingTime = t
				}
			}
		}

		messages = append(messages, domain.Message{
			ID:           id,
			SenderCompID: senderCompID,
			MsgSeqNum:    msgSeqNum,
			SendingTime:  sendingTime,
			CreatedAt:    createdAt,
			JMessage:     jMessage,
		})
	}

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

	return messages, nil
}

func (p *Store) GetLogsByQuoteReqID(quoteReqID string) (domain.Logs, error) {
	selectStmt := "SELECT raw_msg FROM qfixdpl_logs WHERE quote_req_id = '" + quoteReqID + "';"

	response, err := p.db.Query(selectStmt)
	if err != nil {
		return domain.Logs{}, tracerr.Errorf("error querying logs: %w", err)
	}
	defer response.Close()

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

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

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