package node

import (
	"context"
	"net"
	"net/http"
	"os"
	"path/filepath"

	"github.com/DeBrosOfficial/network/pkg/gateway"
	"github.com/DeBrosOfficial/network/pkg/ipfs"
	"github.com/DeBrosOfficial/network/pkg/logging"
	"github.com/DeBrosOfficial/network/pkg/namespace"
	"go.uber.org/zap"
)

// startHTTPGateway initializes and starts the full API gateway
// The gateway always runs HTTP on the configured port (default :6001).
// When running with Caddy (nameserver mode), Caddy handles external HTTPS
// and proxies requests to this internal HTTP gateway.
func (n *Node) startHTTPGateway(ctx context.Context) error {
	if !n.config.HTTPGateway.Enabled {
		n.logger.ComponentInfo(logging.ComponentNode, "HTTP Gateway disabled in config")
		return nil
	}

	logFile := filepath.Join(os.ExpandEnv(n.config.Node.DataDir), "..", "logs", "gateway.log")
	logsDir := filepath.Dir(logFile)
	_ = os.MkdirAll(logsDir, 0755)

	gatewayLogger, err := logging.NewFileLogger(logging.ComponentGeneral, logFile, false)
	if err != nil {
		return err
	}

	gwCfg := &gateway.Config{
		ListenAddr:        n.config.HTTPGateway.ListenAddr,
		ClientNamespace:   n.config.HTTPGateway.ClientNamespace,
		BootstrapPeers:    n.config.Discovery.BootstrapPeers,
		NodePeerID:        loadNodePeerIDFromIdentity(n.config.Node.DataDir),
		RQLiteDSN:         n.config.HTTPGateway.RQLiteDSN,
		OlricServers:      n.config.HTTPGateway.OlricServers,
		OlricTimeout:      n.config.HTTPGateway.OlricTimeout,
		IPFSClusterAPIURL: n.config.HTTPGateway.IPFSClusterAPIURL,
		IPFSAPIURL:        n.config.HTTPGateway.IPFSAPIURL,
		IPFSTimeout:       n.config.HTTPGateway.IPFSTimeout,
		BaseDomain:        n.config.HTTPGateway.BaseDomain,
	}

	apiGateway, err := gateway.New(gatewayLogger, gwCfg)
	if err != nil {
		return err
	}
	n.apiGateway = apiGateway

	// Wire up ClusterManager for per-namespace cluster provisioning
	if ormClient := apiGateway.GetORMClient(); ormClient != nil {
		baseDataDir := filepath.Join(os.ExpandEnv(n.config.Node.DataDir), "..", "data", "namespaces")
		clusterCfg := namespace.ClusterManagerConfig{
			BaseDomain:  n.config.HTTPGateway.BaseDomain,
			BaseDataDir: baseDataDir,
		}
		clusterManager := namespace.NewClusterManager(ormClient, clusterCfg, n.logger.Logger)
		apiGateway.SetClusterProvisioner(clusterManager)
		n.logger.ComponentInfo(logging.ComponentNode, "Namespace cluster provisioning enabled",
			zap.String("base_domain", clusterCfg.BaseDomain),
			zap.String("base_data_dir", baseDataDir))
	}

	go func() {
		server := &http.Server{
			Addr:    gwCfg.ListenAddr,
			Handler: apiGateway.Routes(),
		}
		n.apiGatewayServer = server

		ln, err := net.Listen("tcp", gwCfg.ListenAddr)
		if err != nil {
			n.logger.ComponentError(logging.ComponentNode, "Failed to bind HTTP gateway",
				zap.String("addr", gwCfg.ListenAddr), zap.Error(err))
			return
		}

		n.logger.ComponentInfo(logging.ComponentNode, "HTTP gateway started",
			zap.String("addr", gwCfg.ListenAddr))
		server.Serve(ln)
	}()

	return nil
}

// startIPFSClusterConfig initializes and ensures IPFS Cluster configuration
func (n *Node) startIPFSClusterConfig() error {
	n.logger.ComponentInfo(logging.ComponentNode, "Initializing IPFS Cluster configuration")

	cm, err := ipfs.NewClusterConfigManager(n.config, n.logger.Logger)
	if err != nil {
		return err
	}
	n.clusterConfigManager = cm

	_ = cm.FixIPFSConfigAddresses()
	if err := cm.EnsureConfig(); err != nil {
		return err
	}

	_ = cm.RepairPeerConfiguration()
	return nil
}
