package store

import (
	"errors"
	"time"
)

const ExportVersion = 1

type TunnelExportItem struct {
	ClientID      uint   `json:"client_id"`
	ClientName    string `json:"client_name,omitempty"`
	Name          string `json:"name"`
	Mode          string `json:"mode"`
	ListenIP      string `json:"listen_ip"`
	ListenPort    int    `json:"listen_port"`
	TargetAddr    string `json:"target_addr"`
	IPForwardMode string `json:"ip_forward_mode"`
	CustomHeaders string `json:"custom_headers"`
	Status        bool   `json:"status"`
}

type HostExportItem struct {
	ClientID      uint   `json:"client_id"`
	ClientName    string `json:"client_name,omitempty"`
	Host          string `json:"host"`
	Location      string `json:"location"`
	Scheme        string `json:"scheme"`
	TargetAddr    string `json:"target_addr"`
	AutoHTTPS     bool   `json:"auto_https"`
	IPForwardMode string `json:"ip_forward_mode"`
	CustomHeaders string `json:"custom_headers"`
	Status        bool   `json:"status"`
}

type TunnelExportDoc struct {
	Version    int                `json:"version"`
	ExportedAt time.Time          `json:"exported_at"`
	Items      []TunnelExportItem `json:"items"`
}

type HostExportDoc struct {
	Version    int              `json:"version"`
	ExportedAt time.Time        `json:"exported_at"`
	Items      []HostExportItem `json:"items"`
}

func TunnelToExportItem(t Tunnel, clientName string) TunnelExportItem {
	return TunnelExportItem{
		ClientID:      t.ClientID,
		ClientName:    clientName,
		Name:          t.Name,
		Mode:          t.Mode,
		ListenIP:      t.ListenIP,
		ListenPort:    t.ListenPort,
		TargetAddr:    t.TargetAddr,
		IPForwardMode: t.IPForwardMode,
		CustomHeaders: t.CustomHeaders,
		Status:        t.Status,
	}
}

func HostToExportItem(h Host, clientName string) HostExportItem {
	return HostExportItem{
		ClientID:      h.ClientID,
		ClientName:    clientName,
		Host:          h.Host,
		Location:      h.Location,
		Scheme:        h.Scheme,
		TargetAddr:    h.TargetAddr,
		AutoHTTPS:     h.AutoHTTPS,
		IPForwardMode: h.IPForwardMode,
		CustomHeaders: h.CustomHeaders,
		Status:        h.Status,
	}
}

func (s *Store) FindTunnelByPort(port int) (*Tunnel, error) {
	var t Tunnel
	if err := s.db.Where("listen_port = ?", port).First(&t).Error; err != nil {
		return nil, err
	}
	return &t, nil
}

func (s *Store) FindHostByRouteGlobal(host, location string) (*Host, error) {
	if location == "" {
		location = "/"
	}
	var h Host
	if err := s.db.Where("host = ? AND location = ?", host, location).First(&h).Error; err != nil {
		return nil, err
	}
	return &h, nil
}

func (s *Store) GetClientByName(name string) (*Client, error) {
	var c Client
	if err := s.db.Where("name = ?", name).First(&c).Error; err != nil {
		return nil, err
	}
	return &c, nil
}

func (s *Store) FindTunnelByListen(clientID uint, listenIP string, listenPort int) (*Tunnel, error) {
	if listenIP == "" {
		listenIP = "0.0.0.0"
	}
	var t Tunnel
	if err := s.db.Where("client_id = ? AND listen_ip = ? AND listen_port = ?", clientID, listenIP, listenPort).First(&t).Error; err != nil {
		return nil, err
	}
	return &t, nil
}

func (s *Store) FindHostByRoute(clientID uint, host, location string) (*Host, error) {
	if location == "" {
		location = "/"
	}
	var h Host
	if err := s.db.Where("client_id = ? AND host = ? AND location = ?", clientID, host, location).First(&h).Error; err != nil {
		return nil, err
	}
	return &h, nil
}

func ResolveImportClientID(s *Store, clientID uint, clientName string, ownerID uint, isAdmin bool) (uint, error) {
	if clientID > 0 {
		if err := ClientOwnerCheck(s, clientID, ownerID, isAdmin); err != nil {
			return 0, err
		}
		return clientID, nil
	}
	if clientName == "" {
		return 0, errors.New("client_id or client_name required")
	}
	c, err := s.GetClientByName(clientName)
	if err != nil {
		return 0, errors.New("client not found: " + clientName)
	}
	if err := ClientOwnerCheck(s, c.ID, ownerID, isAdmin); err != nil {
		return 0, err
	}
	return c.ID, nil
}
