package localserver

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
)

const (
	CREATE_NOTIFICATION = "create_notification"
)

const (
	NOTIFY = "notify"
)

type ZoneNotificationsHandler struct {
	ZoneId        string
	ZoneMembersId []string
	DataChannels  map[string]*DataChannel
	Flag          *uint32
	DB            *ZoneNotificationDBHandler
	Publishers    []<-chan *ZoneRequest
	reqChans      []chan<- *ZoneRequest
}

func NewZoneNotificationsHandler(_ string, zoneId string, owner string, authorizedMembers []string, dataChannels map[string]*DataChannel, flag *uint32) (zoneNotificationsHandler *ZoneNotificationsHandler, err error) {
	db, err := NewZoneNotificationDBHandler(zoneId)
	if err != nil {
		return
	}
	if _, dirErr := os.ReadDir(filepath.Join(dataPath, "data", "zones", zoneId, "notifications")); os.IsNotExist(dirErr) {
		dirErr := os.MkdirAll(filepath.Join(dataPath, "data", "zones", zoneId, "notifications"), 0700)
		if dirErr != nil {
			return
		}
	}
	zoneNotificationsHandler = &ZoneNotificationsHandler{
		ZoneId:        zoneId,
		ZoneMembersId: authorizedMembers,
		DataChannels:  dataChannels,
		DB:            db,
		Flag:          flag,
	}
	return
}

// func (znh *ZoneNotificationsHandler) sendZoneRequest(reqType string, from string, payload map[string]interface{}) {
// 	go func() {
// 		for _, rc := range znh.reqChans {
// 			rc <- &ZoneRequest{
// 				ReqType: reqType,
// 				From:    from,
// 				Payload: payload,
// 			}
// 		}
// 	}()
// }

// func (znh *ZoneNotificationsHandler) sendDataChannelMessage(reqType string, from string, to string, payload map[string]interface{}) (<-chan struct{}, <-chan error) {
// 	done, errCh := make(chan struct{}), make(chan error)
// 	go func() {
// 		if err := atomicallyExecute(znh.Flag, func() (err error) {
// 			if _, ok := znh.DataChannels[to]; ok {
// 				bs, jsonErr := json.Marshal(&ZoneResponse{
// 					Type:    reqType,
// 					From:    from,
// 					To:      to,
// 					Payload: payload,
// 				})
// 				if jsonErr != nil {
// 					return jsonErr
// 				}
// 				err = znh.DataChannels[to].DataChannel.SendText(string(bs))
// 			}
// 			return
// 		}); err != nil {
// 			errCh <- err
// 			return
// 		}
// 		done <- struct{}{}
// 	}()
// 	return done, errCh
// }

func (znh *ZoneNotificationsHandler) Init(ctx context.Context, authorizedMembers []string) (err error) {
	//? initialization code here
	return
}

func (znh *ZoneNotificationsHandler) Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error) {
	reqChan, done, errCh = make(chan *ZoneRequest), make(chan struct{}), make(chan error)
	znh.reqChans = append(znh.reqChans, reqChan)
	go func() {
		for {
			select {
			case <-ctx.Done():
				done <- struct{}{}
				return
			case req := <-publisher:
				if err := znh.handleZoneRequest(ctx, req); err != nil {
					errCh <- err
				}
			}
		}
	}()
	return
}

func (znh *ZoneNotificationsHandler) ListNotifications(userId string) {}

func (znh *ZoneNotificationsHandler) CreateNotification(notificationType, title, body, payload string, isPushed bool, recipients ...string) (err error) {
	if isPushed {
		err = znh.PushNotification(notificationType, title, body, payload, recipients...)
	}
	return
}

func (znh *ZoneNotificationsHandler) DeleteNotification() {}

func (znh *ZoneNotificationsHandler) PushNotification(notificationType, title, body, payload string, recipients ...string) (err error) {
	em := NewEncryptionManager()
	sig := em.SignRequestHMAC(NodeID)
	b, err := json.Marshal(map[string]interface{}{
		"type":     NOTIFY,
		"mac":      sig,
		"from":     NodeID,
		"peerType": "node",
		"payload": map[string]interface{}{
			"type":       notificationType,
			"title":      title,
			"body":       body,
			"recipients": recipients,
			"payload":    payload,
		},
	})
	if err != nil {
		return
	}
	_, err = HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewReader(b))
	if err != nil {
		logger.Println("error come from there in zone manager")
		return
	}
	return
}

func (znh ZoneNotificationsHandler) handleDataChannel(ctx context.Context, dc *DataChannel) (catched bool) {
	return
}

func (znh *ZoneNotificationsHandler) handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error) {
	switch req.ReqType {
	case CREATE_NOTIFICATION:
		if err = verifyFieldsString(req.Payload, "type", "title", "body", "payload"); err != nil {
			return
		}
		if err = verifyFieldsBool(req.Payload, "isPushed"); err != nil {
			return
		}
		if _, ok := req.Payload["recipients"]; !ok {
			err = fmt.Errorf("no field recipient in payload")
			return
		}
		if _, ok := req.Payload["recipients"].([]string); !ok {
			err = fmt.Errorf(" field recipient in payload is wrong type")
			return
		}
		// recipients := []string{}
		// for _, recipient := range req.Payload["recipients"].([]any) {
		// 	if r, ok := recipient.(string); ok {
		// 		recipients = append(recipients, r)
		// 	}
		// }

		err = znh.CreateNotification(req.Payload["type"].(string), req.Payload["title"].(string), req.Payload["body"].(string), req.Payload["payload"].(string), req.Payload["isPushed"].(bool), req.Payload["recipients"].([]string)...)
	}
	return
}
