package fix

import (
	"time"

	"quantex.com/qfixdpl/quickfix"
	"quantex.com/qfixdpl/quickfix/gen/fix50sp2/executionreport"
	"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoteack"
	"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoterequest"
	"quantex.com/qfixdpl/quickfix/gen/fix50sp2/quoteresponse"
	"quantex.com/qfixdpl/quickfix/gen/tag"
	"quantex.com/qfixdpl/src/domain"
)

func extractHeader(msg *quickfix.Message) map[string]interface{} {
	header := make(map[string]interface{})

	if v, err := msg.Header.GetBytes(tag.BeginString); err == nil {
		header["BeginString"] = string(v)
	}
	if v, err := msg.Header.GetBytes(tag.MsgType); err == nil {
		header["MsgType"] = string(v)
	}
	if v, err := msg.Header.GetBytes(tag.SenderCompID); err == nil {
		header["SenderCompID"] = string(v)
	}
	if v, err := msg.Header.GetBytes(tag.TargetCompID); err == nil {
		header["TargetCompID"] = string(v)
	}
	if v, err := msg.Header.GetBytes(tag.MsgSeqNum); err == nil {
		header["MsgSeqNum"] = string(v)
	}
	if v, err := msg.Header.GetBytes(tag.SendingTime); err == nil {
		header["SendingTime"] = string(v)
	}

	return header
}

func parseQuoteRequest(msg quoterequest.QuoteRequest) domain.FixMessageJSON {
	quoteReqID, _ := msg.GetQuoteReqID()
	body := map[string]interface{}{"QuoteReqID": quoteReqID}

	if relSyms, err := msg.GetNoRelatedSym(); err == nil && relSyms.Len() > 0 {
		sym := relSyms.Get(0)
		if v, e := sym.GetSecurityID(); e == nil {
			body["SecurityID"] = v
		}
		if v, e := sym.GetSecurityIDSource(); e == nil {
			body["SecurityIDSource"] = string(v)
		}
		if v, e := sym.GetCurrency(); e == nil {
			body["Currency"] = v
		}
		if v, e := sym.GetSide(); e == nil {
			body["Side"] = string(v)
		}
		if v, e := sym.GetOrderQty(); e == nil {
			body["OrderQty"] = v.String()
		}
		if v, e := sym.GetSettlDate(); e == nil {
			body["SettlDate"] = v
		}
		if v, e := sym.GetListID(); e == nil {
			body["ListID"] = v
		}
		if v, e := sym.GetOwnerTraderID(); e == nil {
			body["OwnerTraderID"] = v
		}
		if v, e := sym.GetNegotiationType(); e == nil {
			body["NegotiationType"] = v
		}
	}

	return domain.FixMessageJSON{
		Direction:   "IN",
		MsgType:     "R",
		QuoteReqID:  quoteReqID,
		Header:      extractHeader(msg.Message),
		Body:        body,
		ReceiveTime: time.Now(),
	}
}

func parseQuoteAck(msg quoteack.QuoteAck) domain.FixMessageJSON {
	quoteReqID, _ := msg.GetQuoteReqID()
	body := map[string]interface{}{"QuoteReqID": quoteReqID}

	if v, e := msg.GetQuoteID(); e == nil {
		body["QuoteID"] = v
	}
	if v, e := msg.GetQuoteAckStatus(); e == nil {
		body["QuoteAckStatus"] = string(v)
	}
	if v, e := msg.GetText(); e == nil {
		body["Text"] = v
	}

	return domain.FixMessageJSON{
		Direction:   "IN",
		MsgType:     "CW",
		QuoteReqID:  quoteReqID,
		Header:      extractHeader(msg.Message),
		Body:        body,
		ReceiveTime: time.Now(),
	}
}

func parseQuoteResponse(msg quoteresponse.QuoteResponse) domain.FixMessageJSON {
	quoteReqID, _ := msg.GetQuoteReqID()
	body := map[string]interface{}{"QuoteReqID": quoteReqID}

	if v, e := msg.GetQuoteRespID(); e == nil {
		body["QuoteRespID"] = v
	}
	if v, e := msg.GetQuoteRespType(); e == nil {
		body["QuoteRespType"] = string(v)
	}
	if v, e := msg.GetSide(); e == nil {
		body["Side"] = string(v)
	}
	if v, e := msg.GetPrice(); e == nil {
		body["Price"] = v.String()
	}
	if v, e := msg.GetOrderQty(); e == nil {
		body["OrderQty"] = v.String()
	}
	if v, e := msg.GetClOrdID(); e == nil {
		body["ClOrdID"] = v
	}

	return domain.FixMessageJSON{
		Direction:   "IN",
		MsgType:     "AJ",
		QuoteReqID:  quoteReqID,
		Header:      extractHeader(msg.Message),
		Body:        body,
		ReceiveTime: time.Now(),
	}
}

func parseExecutionReport(msg executionreport.ExecutionReport) domain.FixMessageJSON {
	clOrdID, _ := msg.GetClOrdID()
	body := map[string]interface{}{"ClOrdID": clOrdID}

	if v, e := msg.GetExecID(); e == nil {
		body["ExecID"] = v
	}
	if v, e := msg.GetOrderID(); e == nil {
		body["OrderID"] = v
	}
	if v, e := msg.GetExecType(); e == nil {
		body["ExecType"] = string(v)
	}
	if v, e := msg.GetOrdStatus(); e == nil {
		body["OrdStatus"] = string(v)
	}
	if v, e := msg.GetListID(); e == nil {
		body["ListID"] = v
	}
	if v, e := msg.GetSide(); e == nil {
		body["Side"] = string(v)
	}
	if v, e := msg.GetSymbol(); e == nil {
		body["Symbol"] = v
	}
	if v, e := msg.GetSecurityID(); e == nil {
		body["SecurityID"] = v
	}
	if v, e := msg.GetCurrency(); e == nil {
		body["Currency"] = v
	}
	if v, e := msg.GetPrice(); e == nil {
		body["Price"] = v.String()
	}
	if v, e := msg.GetLastPx(); e == nil {
		body["LastPx"] = v.String()
	}
	if v, e := msg.GetLastQty(); e == nil {
		body["LastQty"] = v.String()
	}
	if v, e := msg.GetOrderQty(); e == nil {
		body["OrderQty"] = v.String()
	}
	if v, e := msg.GetSettlDate(); e == nil {
		body["SettlDate"] = v
	}
	if v, e := msg.GetTradeID(); e == nil {
		body["TradeID"] = v
	}

	return domain.FixMessageJSON{
		Direction:   "IN",
		MsgType:     "8",
		QuoteReqID:  clOrdID,
		Header:      extractHeader(msg.Message),
		Body:        body,
		ReceiveTime: time.Now(),
	}
}

// extractIdentifier extracts the trade identifier from a parsed FIX message.
// For ExecutionReport (8) and ExecutionAck (BN), uses ClOrdID (tag 11).
// For all other message types, uses QuoteReqID (tag 131).
func extractIdentifier(msg *quickfix.Message) string {
	msgType, _ := msg.Header.GetBytes(tag.MsgType)

	switch string(msgType) {
	case "8", "BN":
		var clOrdID quickfix.FIXString
		if err := msg.Body.GetField(tag.ClOrdID, &clOrdID); err == nil {
			return string(clOrdID)
		}
	default:
		var quoteReqID quickfix.FIXString
		if err := msg.Body.GetField(tag.QuoteReqID, &quoteReqID); err == nil {
			return string(quoteReqID)
		}
	}

	return ""
}

func buildOutgoingMessageJSON(msgType, quoteReqID string, body map[string]interface{}) domain.FixMessageJSON {
	return domain.FixMessageJSON{
		Direction:   "OUT",
		MsgType:     msgType,
		QuoteReqID:  quoteReqID,
		Body:        body,
		ReceiveTime: time.Now(),
	}
}
