package dto

import (
	"fmt"
	"net/url"
	"strings"
)

// DataSourceInfo 数据源信息
type DataSourceInfo struct {
	Scheme       string // s3, gs, oss, https, abfs, abfss
	Vendor       string // aws, gcp, alicloud, azure
	Region       string // us-east-1, asia-northeast1, ap-southeast-1, southeastasia
	Bucket       string // bucket 名称；Azure 中兼容表示 container
	Path         string // 对象路径
	FullURI      string // 完整 URI
	Account      string // Azure storage account
	Container    string // Azure container / filesystem
	CanonicalURI string // Azure Synapse OPENROWSET 推荐 URI
}

// ParseDataSource 解析数据源 URI
func ParseDataSource(uri string) (*DataSourceInfo, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return nil, fmt.Errorf("invalid URI: %w", err)
	}

	info := &DataSourceInfo{
		Scheme:  u.Scheme,
		Bucket:  u.Host,
		Path:    strings.TrimPrefix(u.Path, "/"),
		FullURI: uri,
	}

	// 识别云厂商
	switch u.Scheme {
	case "s3":
		info.Vendor = "aws"
	case "gs":
		info.Vendor = "gcp"
	case "oss":
		info.Vendor = "alicloud"
	case "https":
		if !parseAzureHTTPSDataSource(u, info) {
			return nil, fmt.Errorf("unsupported https data source host: %s", u.Host)
		}
	case "abfs", "abfss":
		parseAzureABFSDataSource(u, info)
	default:
		return nil, fmt.Errorf("unsupported scheme: %s", u.Scheme)
	}

	return info, nil
}

// String 返回数据源的字符串表示
func (d *DataSourceInfo) String() string {
	if d.CanonicalURI != "" {
		return d.CanonicalURI
	}
	return fmt.Sprintf("%s://%s/%s", d.Scheme, d.Bucket, d.Path)
}

func parseAzureHTTPSDataSource(u *url.URL, info *DataSourceInfo) bool {
	host := strings.ToLower(u.Host)
	const dfsSuffix = ".dfs.core.windows.net"
	const blobSuffix = ".blob.core.windows.net"

	var account string
	switch {
	case strings.HasSuffix(host, dfsSuffix):
		account = strings.TrimSuffix(host, dfsSuffix)
	case strings.HasSuffix(host, blobSuffix):
		account = strings.TrimSuffix(host, blobSuffix)
	default:
		return false
	}

	path := strings.TrimPrefix(u.Path, "/")
	container, rest, ok := splitFirstPathSegment(path)
	if !ok {
		return false
	}

	info.Vendor = "azure"
	info.Account = account
	info.Container = container
	info.Bucket = container
	info.Path = rest
	info.CanonicalURI = buildAzureDFSURI(account, container, rest)
	return true
}

func parseAzureABFSDataSource(u *url.URL, info *DataSourceInfo) {
	info.Vendor = "azure"
	info.Path = strings.TrimPrefix(u.Path, "/")

	if u.User != nil {
		info.Container = u.User.Username()
		info.Account = azureAccountFromHost(u.Host)
	} else {
		info.Container = u.Host
	}
	info.Bucket = info.Container

	if info.Account != "" && info.Container != "" {
		info.CanonicalURI = buildAzureDFSURI(info.Account, info.Container, info.Path)
	}
}

func splitFirstPathSegment(path string) (first string, rest string, ok bool) {
	path = strings.TrimPrefix(path, "/")
	if path == "" {
		return "", "", false
	}
	parts := strings.SplitN(path, "/", 2)
	if parts[0] == "" {
		return "", "", false
	}
	if len(parts) == 1 {
		return parts[0], "", true
	}
	return parts[0], parts[1], true
}

func azureAccountFromHost(host string) string {
	host = strings.ToLower(host)
	host = strings.TrimSuffix(host, ".dfs.core.windows.net")
	host = strings.TrimSuffix(host, ".blob.core.windows.net")
	return host
}

func buildAzureDFSURI(account, container, path string) string {
	base := fmt.Sprintf("https://%s.dfs.core.windows.net/%s", account, container)
	path = strings.TrimPrefix(path, "/")
	if path == "" {
		return base
	}
	return base + "/" + path
}
