// Package fix implements the QuickFIX initiator application.
package fix

import (
	"log/slog"

	"quantex.com/qfixdpl/quickfix"
	"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quote"
	"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoterequest"
	"quantex.com/qfixdpl/quickfix/gen/tag"
	"quantex.com/qfixdpl/src/domain"
)

type application struct {
	router   *quickfix.MessageRouter
	notifier domain.Notifier
	onLogon  func(quickfix.SessionID)
	onLogout func(quickfix.SessionID)
	onQuote  func(quote.Quote, quickfix.SessionID)
}

func newApplication(n domain.Notifier) *application {
	app := &application{
		router:   quickfix.NewMessageRouter(),
		notifier: n,
	}

	app.router.AddRoute(quote.Route(app.handleQuote))
	app.router.AddRoute(quoterequest.Route(app.handleQuoteRequest))

	return app
}

func (a *application) OnCreate(sessionID quickfix.SessionID) {
	slog.Info("FIX session created", "session", sessionID.String())
}

func (a *application) OnLogon(sessionID quickfix.SessionID) {
	slog.Info("FIX session logged on", "session", sessionID.String())
	if a.onLogon != nil {
		a.onLogon(sessionID)
	}
}

func (a *application) OnLogout(sessionID quickfix.SessionID) {
	slog.Info("FIX session logged out", "session", sessionID.String())

	go a.notifier.SendMsg(domain.MessageChannelError, "Logout", domain.MessageStatusWarning, nil)

	if a.onLogout != nil {
		a.onLogout(sessionID)
	}
}

func (a *application) ToAdmin(_ *quickfix.Message, _ quickfix.SessionID) {}

func (a *application) ToApp(_ *quickfix.Message, _ quickfix.SessionID) error { return nil }

func (a *application) FromAdmin(_ *quickfix.Message, _ quickfix.SessionID) quickfix.MessageRejectError {
	return nil
}

func (a *application) FromApp(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
	beginString, _ := msg.Header.GetBytes(tag.BeginString)
	msgType, _ := msg.Header.GetBytes(tag.MsgType)

	var applVerID quickfix.FIXString
	msg.Header.GetField(tag.ApplVerID, &applVerID)

	slog.Info("FIX FromApp received",
		"beginString", string(beginString),
		"msgType", string(msgType),
		"applVerID", string(applVerID),
		"session", sessionID.String(),
		"rawMsg", msg.String(),
	)

	rejErr := a.router.Route(msg, sessionID)
	if rejErr != nil {
		slog.Error("FIX FromApp routing failed",
			"msgType", string(msgType),
			"error", rejErr.Error(),
			"isBusinessReject", rejErr.IsBusinessReject(),
		)
	}

	return rejErr
}

func (a *application) handleQuoteRequest(msg quoterequest.QuoteRequest, sessionID quickfix.SessionID) quickfix.MessageRejectError {
	quoteReqID, err := msg.GetQuoteReqID()
	if err != nil {
		slog.Error("QuoteRequest missing QuoteReqID", "error", err.Error())
		return err
	}

	slog.Info("QuoteRequest received",
		"quoteReqID", quoteReqID,
		"session", sessionID.String(),
	)

	return nil
}

func (a *application) handleQuote(msg quote.Quote, sessionID quickfix.SessionID) quickfix.MessageRejectError {
	quoteID, err := msg.GetQuoteID()
	if err != nil {
		return err
	}

	symbol, _ := msg.GetSymbol()

	slog.Info("Quote received", "quoteID", quoteID, "symbol", symbol, "session", sessionID.String())

	if a.onQuote != nil {
		a.onQuote(msg, sessionID)
	}

	return nil
}
