package api

import (
	"context"
	"encoding/base64"
	"encoding/json"

	"github.com/google/uuid"
)

type PortItem interface {
	Params() PortParams
	Close() error
	Run(ctx context.Context) error
}

type PortParams struct {
	Uuid uuid.UUID
	Host string
	Port int
	// 0 - open
	// 1 - listen
	// 2 - redirect
	Mode int

	LinkTo    PortParamsLinkTo
	Handshake PortParamsHandshake
	Encrypt   PortParamsEncrypt
}

func (p PortParams) MarshalJSON() ([]byte, error) {
	jsonData := map[string]any{
		"uuid":      p.Uuid,
		"host":      p.Host,
		"port":      p.Port,
		"mode":      p.Mode,
		"link_to":   p.LinkTo,
		"handshake": p.Handshake,
		"encrypt":   p.Encrypt,
	}
	return json.Marshal(jsonData)
}

func (p *PortParams) UnmarshalJSON(data []byte) error {
	jsonData := map[string]any{}
	if err := json.Unmarshal(data, &jsonData); err != nil {
		return err
	}
	if val, ok := jsonData["uuid"].(string); ok {
		parsedUuid, err := uuid.Parse(val)
		if err != nil {
			return err
		}
		p.Uuid = parsedUuid
	}
	if val, ok := jsonData["host"].(string); ok {
		p.Host = val
	}
	if val, ok := jsonData["port"].(float64); ok {
		p.Port = int(val)
	}
	if val, ok := jsonData["mode"].(float64); ok {
		p.Mode = int(val)
	}
	if val, ok := jsonData["link_to"].(map[string]any); ok {
		linkToData, err := json.Marshal(val)
		if err != nil {
			return err
		}
		if err = json.Unmarshal(linkToData, &p.LinkTo); err != nil {
			return err
		}
	}
	if val, ok := jsonData["handshake"].(map[string]any); ok {
		handshakeData, err := json.Marshal(val)
		if err != nil {
			return err
		}
		if err = json.Unmarshal(handshakeData, &p.Handshake); err != nil {
			return err
		}
	}
	if val, ok := jsonData["encrypt"].(map[string]any); ok {
		encryptData, err := json.Marshal(val)
		if err != nil {
			return err
		}
		if err = json.Unmarshal(encryptData, &p.Encrypt); err != nil {
			return err
		}
	}
	return nil
}

type PortParamsLinkTo struct {
	Host string
	Port int
}

func (l PortParamsLinkTo) MarshalJSON() ([]byte, error) {
	jsonData := map[string]any{
		"host": l.Host,
		"port": l.Port,
	}
	return json.Marshal(jsonData)
}

func (l *PortParamsLinkTo) UnmarshalJSON(data []byte) error {
	jsonData := map[string]any{}
	if err := json.Unmarshal(data, &jsonData); err != nil {
		return err
	}
	if val, ok := jsonData["host"].(string); ok {
		l.Host = val
	}
	if val, ok := jsonData["port"].(float64); ok {
		l.Port = int(val)
	}
	return nil
}

type PortParamsHandshake struct {
	Key   []byte
	Value []byte
}

func (h PortParamsHandshake) MarshalJSON() ([]byte, error) {
	jsonData := map[string]any{
		"key":   h.Key,
		"value": h.Value,
	}
	return json.Marshal(jsonData)
}

func (h *PortParamsHandshake) UnmarshalJSON(data []byte) error {
	jsonData := map[string]any{}
	if err := json.Unmarshal(data, &jsonData); err != nil {
		return err
	}
	if val, ok := jsonData["key"].(string); ok {
		key, err := base64.StdEncoding.DecodeString(val)
		if err != nil {
			return err
		}
		h.Key = key
	}
	if val, ok := jsonData["value"].(string); ok {
		value, err := base64.StdEncoding.DecodeString(val)
		if err != nil {
			return err
		}
		h.Value = value
	}
	return nil
}

type PortParamsEncrypt struct {
	Name string
	Key  []byte
}

func (e PortParamsEncrypt) MarshalJSON() ([]byte, error) {
	jsonData := map[string]any{
		"name": e.Name,
		"key":  e.Key,
	}
	return json.Marshal(jsonData)
}

func (e *PortParamsEncrypt) UnmarshalJSON(data []byte) error {
	jsonData := map[string]any{}
	if err := json.Unmarshal(data, &jsonData); err != nil {
		return err
	}
	if val, ok := jsonData["name"].(string); ok {
		e.Name = val
	}
	if val, ok := jsonData["key"].(string); ok {
		key, err := base64.StdEncoding.DecodeString(val)
		if err != nil {
			return err
		}
		e.Key = key
	}
	return nil
}

var PortStatusOk = 1
var PortStatusError = 2
