package auth

import (
	"fmt"
	"net"
	"proxy-server/gateway/app"
	"proxy-server/gateway/core"
	"proxy-server/gateway/env"
	"slices"
	"strconv"
	"time"

	"errors"
)

type Protocol string

const (
	Socks5 = Protocol("socks5")
	Http   = Protocol("http")
)

func Protect(conn net.Conn, proto Protocol, username, password *string) (*core.AuthContext, error) {

	// 获取用户地址
	remoteAddr := conn.RemoteAddr().String()
	remoteHost, _, err := net.SplitHostPort(remoteAddr)
	if err != nil {
		return nil, fmt.Errorf("无法获取连接信息: %w", err)
	}

	// 获取服务端口
	localAddr := conn.LocalAddr().String()
	_, _localPort, err := net.SplitHostPort(localAddr)
	localPort, err := strconv.ParseUint(_localPort, 10, 16)
	if err != nil {
		return nil, fmt.Errorf("noAuth 认证失败: %w", err)
	}

	var id, _ = app.Assigns.Load(uint16(localPort))

	// 检查全局白名单
	var remoteIp = net.ParseIP(remoteHost)
	if remoteIp == nil {
		return nil, fmt.Errorf("无法解析 IP 地址: %s", remoteHost)
	}
	if slices.ContainsFunc(env.AuthWhitelist, func(ip net.IP) bool { return ip.Equal(remoteIp) }) {
		return &core.AuthContext{
			Payload: core.Payload{
				ID: id,
			},
		}, nil
	}

	// 查找权限配置
	var permit = app.LoadPermit(uint16(localPort))
	if permit == nil {
		return nil, errors.New("没有权限")
	}

	// 检查是否过期
	if permit.Expire.Before(time.Now()) {
		return nil, errors.New("权限已过期")
	}

	// 检查 IP 是否可用
	if permit.Whitelists != nil && len(*permit.Whitelists) > 0 {
		var found = false
		for _, allowedHost := range *permit.Whitelists {
			var allowed = net.ParseIP(allowedHost)
			var remote = net.ParseIP(remoteHost)
			if remote.Equal(allowed) {
				found = true
				break
			}
		}
		if !found {
			return nil, errors.New("不在白名单内")
		}
	}

	if permit.Username != nil || permit.Password != nil {
		if *username != *permit.Username || *password != *permit.Password {
			return nil, errors.New("用户名或密码错误")
		}
	}

	return &core.AuthContext{
		Payload: core.Payload{
			ID: id,
		},
	}, nil
}
