package server

import (
	"PD1/internal/protocol"
	"PD1/internal/utils/cryptoUtils"
	"PD1/internal/utils/networking"
	"log"
)

func clientHandler(connection networking.Connection[protocol.Packet], dataStore DataStore) {
	defer connection.Conn.Close()

	//Get certificate sent by user
	clientCert := connection.GetPeerCertificate()
	//Get the OID values
	oidMap := cryptoUtils.ExtractAllOIDValues(clientCert)
	//Check if certificate usage is MSG SERVICE
	usage := oidMap["2.5.4.11"]
	if usage == "" {
		log.Fatalln("User certificate does not have the correct usage")
	}
	//Get the UID of this user
	UID := oidMap["2.5.4.65"]
	if UID == "" {
		log.Fatalln("User certificate does not specify it's PSEUDONYM")
	}
	err := dataStore.storeUserCertIfNotExists(UID, *clientCert)
	if err != nil {
		log.Fatalln(err)
	}
F:
	for {
		pac, err := connection.Receive()
		if err != nil {
			break
		}
		switch pac.Flag {
		case protocol.FlagGetUserCert:
			reqUserCert, err := protocol.UnmarshalGetUserCert(pac.Body)
			if err != nil {
				log.Fatalln(err)
			}
			userCertPacket := dataStore.GetUserCertificate(reqUserCert.UID)
			if err := connection.Send(userCertPacket); err != nil {
				log.Fatalln(err)
				break F
			}

		case protocol.FlagGetUnreadMsgsInfo:
			getUnreadMsgsInfo, err := protocol.UnmarshalGetUnreadMsgsInfo(pac.Body)
			if err != nil {
				log.Fatalln(err)
			}
			var messages protocol.Packet
			if getUnreadMsgsInfo.Page <= 0 || getUnreadMsgsInfo.PageSize <= 0 {
				messages = protocol.NewReportErrorPacket("Page and PageSize need to be >= 1")
			} else {
				messages, err = dataStore.GetUnreadMsgsInfo(UID, getUnreadMsgsInfo.Page, getUnreadMsgsInfo.PageSize)
				if err != nil {
					log.Fatalln(err)
				}
			}
			if err := connection.Send(messages); err != nil {
				log.Fatalln(err)
			}

		case protocol.FlagGetMsg:
			reqMsg, err := protocol.UnmarshalGetMsg(pac.Body)
			if err != nil {
				log.Fatalln(err)
			}
			var message protocol.Packet
			if reqMsg.Num <= 0 {
				message = protocol.NewReportErrorPacket("Message NUM needs to be >= 1")
			} else {
				message = dataStore.GetMessage(UID, reqMsg.Num)
			}
			if err := connection.Send(message); err != nil {
				log.Fatalln(err)
				break F
			}
			dataStore.MarkMessageInQueueAsRead(UID, reqMsg.Num)

		case protocol.FlagSendMsg:
			submitMsg, err := protocol.UnmarshalSendMsg(pac.Body)
			if err != nil {
				log.Fatalln(err)
			}
			var answerSendMsgPacket protocol.Packet
			if submitMsg.ToUID == UID {
				answerSendMsgPacket = protocol.NewReportErrorPacket("Message sender and receiver cannot be the same user")
			} else if !dataStore.userExists(submitMsg.ToUID) {
				answerSendMsgPacket = protocol.NewReportErrorPacket("Message receiver does not exist")
			} else {
				answerSendMsgPacket = dataStore.AddMessageToQueue(UID, submitMsg)
			}
			if err := connection.Send(answerSendMsgPacket); err != nil {
				log.Fatalln(err)
				break F
			}
		}
	}
}

func Run() {
	//Open connection to DB
	dataStore, err := OpenDB()
	if err != nil {
		log.Fatalln(err)
	}
	defer dataStore.db.Close()

	//Read server keystore
	keystorePassphrase := readStdin("Insert keystore passphrase")
	serverKeyStore, err := cryptoUtils.LoadKeyStore("certs/server/server.p12", keystorePassphrase)
	if err != nil {
		log.Fatalln(err)
	}

	//Create server listener
	server, err := networking.NewServer[protocol.Packet](&serverKeyStore)
	if err != nil {
		log.Fatalln(err)
	}
	go server.ListenLoop()

	for {
		//Receive Connection via channel
		conn := <-server.C
		//Launch client handler via clientHandler
		go clientHandler(conn, dataStore)
	}
}