package main

import (
	"errors"
	"fmt"
	"gitea.unprism.ru/KRBL/n9m/v2/pkg/models"
	"gitea.unprism.ru/KRBL/n9m/v2/pkg/protocol"
	"gitea.unprism.ru/KRBL/n9m/v2/pkg/smart"
	"gitea.unprism.ru/KRBL/n9m/v2/pkg/utils"
	"io"
	"net"
	"os"
	"syscall"
)

var videoPack *smart.SmartChannelPackage

func main() {
	conn, err := net.Dial("tcp", "10.100.100.99:9006")

	if err != nil {
		panic(err)
	}

	var pack = protocol.Package{}

	pack.Payload.Module = "CERTIFICATE"
	pack.Payload.Operation = "CONNECT"
	pack.SetParameters(models.CertificateConnectClientRequest{})
	conn.Write(pack.PackPackage())

	handle(conn)
}

func handleSpecialPackages(_ *smart.SmartPackage, pack protocol.Package) error {
	switch pack.SSRC {
	case protocol.SpecialPayloadTypeGPS:
		fmt.Printf("%+v\n", pack.GPS)
		return nil
	default:
		return fmt.Errorf("unhandled special operation: %d", pack.SSRC)
	}
}

func handleLivePackages(_ *smart.SmartPackage, pack protocol.Package) error {
	fmt.Printf("%+v\n", pack)

	return nil
}

func handleCertificateConnect(sPack *smart.SmartPackage, pack protocol.Package) (err error) {
	var params models.CertificateConnectClientResponse

	if err = pack.GetResponseAs(&params); err != nil {
		return fmt.Errorf("failed to get response: %w", err)
	}

	var response = models.CertificateVerificationRequest{
		S0: utils.GenerateVerifyKey(params.S0),
	}

	pack.Payload.Operation = "VERIFY"
	pack.SetParameters(response)

	sPack.Write(pack.PackPackage())

	return
}

func handleVerify(sPack *smart.SmartPackage, pack protocol.Package) (err error) {
	var params models.CertificateVerificationResponse

	if err = pack.GetResponseAs(&params); err != nil {
		return fmt.Errorf("failed to get response: %w", err)
	}

	if params.ErrorCode == 0 {
		fmt.Println("ШАЛОСТЬ УДАЛАСЬ!")
	} else {
		fmt.Println("шалость НЕ удалась(((")
	}

	var request = models.CertificateLoginRequest{
		ClientID: 0,
		MAC:      "",
		User:     "admin",
		Password: "",
	}

	pack.Payload.Operation = "LOGIN"
	pack.SetParameters(request)

	sPack.Write(pack.PackPackage())

	return
}

func handleLogin(sPack *smart.SmartPackage, pack protocol.Package) (err error) {
	var params models.CertificateLoginResponse

	if err = pack.GetResponseAs(&params); err != nil {
		return fmt.Errorf("failed to get response: %w", err)
	}

	conn, err := net.Dial("tcp", "10.100.100.99:9006")

	if err != nil {
		panic(err)
	}

	videoPack, err = smart.NewSmartChannelPackage(conn, sPack)

	if err != nil {
		panic(err)
	}

	go videoPack.Run()

	videoPack.AddLiveSource(2, func(data []byte) error {
		fmt.Println("Есть контакт!")
		return nil
	})

	var request = models.MediaStreamModelRequestLiveVideoRequest{
		StreamName: videoPack.GetChannelName(),
		StreamType: models.StreamTypeMain,
		Channel:    4,
		AudioValid: 4,
		FrameMode:  0,
	}

	pack.Payload.Module = "MEDIASTREAMMODEL"
	pack.Payload.Operation = "REQUESTALIVEVIDEO"
	pack.SetParameters(request)

	sPack.Write(pack.PackPackage())

	return
}

func handleRequestLiveVideo(sPack *smart.SmartPackage, pack protocol.Package) (err error) {
	var params models.MediaStreamModelRequestLiveVideoResponse

	if err = pack.GetResponseAs(&params); err != nil {
		return fmt.Errorf("failed to get response: %w", err)
	}

	if params.ErrorCode != 0 {
		fmt.Println("Request live stream error:", params.ErrorCode, params.ErrorCause)
		return
	}

	fmt.Printf("%+v\n", params)

	return
}

func handleKeepAlive(sPack *smart.SmartPackage, pack protocol.Package) (err error) {
	serial := sPack.Storage["serial"]
	fmt.Println(serial, "still alive!")

	pack.SetResponse(nil)
	sPack.Write(pack.PackPackage())

	return
}

func handleGetConfig(sPack *smart.SmartPackage, pack protocol.Package) (err error) {
	serial := sPack.Storage["serial"]

	os.WriteFile(fmt.Sprintf("./%s.json", serial), pack.RawPayload, 0644)

	var request models.ConfigModelSetRequest

	if err = pack.GetParametersAs(&request); err != nil {
		fmt.Println(err)
		return err
	}

	return
}

func handleUselessAlarms(sPack *smart.SmartPackage, pack protocol.Package, response models.SendAlarmInfoResponse) (err error) {
	return nil
}

func handleVideoLossAlarm(sPack *smart.SmartPackage, pack protocol.Package, response models.SendAlarmInfoResponse) (err error) {
	fmt.Println("Video loss alarm!")
	return nil
}

func handleCameraCoveredAlarm(sPack *smart.SmartPackage, pack protocol.Package, response models.SendAlarmInfoResponse) (err error) {
	fmt.Println("Camera covered alarm!")
	return nil
}

func handleSPI(_ *smart.SmartPackage, pack protocol.Package) (err error) {
	var params models.SpiParameters

	if err = pack.GetParametersAs(&params); err != nil {
		return
	}

	fmt.Printf("%+v\n", params)

	return
}

func createSmartPackage(conn net.Conn) (pack *smart.SmartPackage) {
	pack = smart.NewSmartPackage(conn)

	pack.AddPayloadHandler(protocol.PayloadTypeLive, handleLivePackages)
	pack.AddPayloadHandler(protocol.PayloadTypeSpecial, handleSpecialPackages)

	pack.AddJSONHandler("CERTIFICATE", "CONNECT", handleCertificateConnect)
	pack.AddJSONHandler("CERTIFICATE", "VERIFY", handleVerify)
	pack.AddJSONHandler("CERTIFICATE", "LOGIN", handleLogin)
	pack.AddJSONHandler("CERTIFICATE", "KEEPALIVE", handleKeepAlive)
	pack.AddJSONHandler("MEDIASTREAMMODEL", "REQUESTALIVEVIDEO", handleRequestLiveVideo)
	pack.AddJSONHandler("CONFIGMODEL", "GET", handleGetConfig)
	pack.AddJSONHandler("DEVEMM", "SPI", handleSPI)

	pack.AddAlarmHandler(protocol.AlarmTypeMotionDetection, handleUselessAlarms)

	pack.AddAlarmHandler(protocol.AlarmTypeVideoLoss, handleVideoLossAlarm)
	pack.AddAlarmHandler(protocol.AlarmTypeCameraCovered, handleCameraCoveredAlarm)

	return
}

func isNetConnClosedErr(err error) bool {
	switch {
	case
		errors.Is(err, net.ErrClosed),
		errors.Is(err, io.EOF),
		errors.Is(err, syscall.EPIPE):
		return true
	default:
		return false
	}
}

func handle(conn net.Conn) {
	pack := createSmartPackage(conn)

	var err error
	for {
		if err = pack.Handle(); err != nil {
			fmt.Println("Error:", err)

			if isNetConnClosedErr(err) {
				return
			}
		}
	}
}