package usecase

import (
	"backend/pkg/permission/domain/entity"
	"backend/pkg/permission/domain/permission"
	"backend/pkg/permission/domain/usecase"
	"fmt"

	"go.mongodb.org/mongo-driver/v2/bson"
)

// PermissionTree 權限樹 (優化版本)
type PermissionTree struct {
	// 所有節點 (ID -> Node)
	nodes map[string]*PermissionNode

	// 根節點列表
	roots []*PermissionNode

	// 名稱索引 (Name -> IDs)
	nameIndex map[string][]string

	// 子節點索引 (ParentID -> Children IDs)
	childrenIndex map[string][]string
}

// PermissionNode 權限節點
type PermissionNode struct {
	Permission *entity.Permission
	Parent     *PermissionNode
	Children   []*PermissionNode
	PathIDs    []string // 從根到此節點的完整路徑 ID
}

// NewPermissionTree 建立權限樹
func NewPermissionTree(permissions []*entity.Permission) *PermissionTree {
	tree := &PermissionTree{
		nodes:         make(map[string]*PermissionNode),
		roots:         make([]*PermissionNode, 0),
		nameIndex:     make(map[string][]string),
		childrenIndex: make(map[string][]string),
	}

	// 第一遍：建立所有節點
	for _, perm := range permissions {
		node := &PermissionNode{
			Permission: perm,
			Children:   make([]*PermissionNode, 0),
			PathIDs:    make([]string, 0),
		}
		idHex := perm.ID.Hex()
		tree.nodes[idHex] = node

		// 建立名稱索引
		tree.nameIndex[perm.Name] = append(tree.nameIndex[perm.Name], idHex)

		// 建立子節點索引
		parentIDHex := perm.ParentID.Hex()
		tree.childrenIndex[parentIDHex] = append(tree.childrenIndex[parentIDHex], idHex)
	}

	// 第二遍：建立父子關係
	for _, node := range tree.nodes {
		if node.Permission.ParentID.IsZero() {
			// 根節點
			tree.roots = append(tree.roots, node)
		} else {
			// 找到父節點並建立關係
			parentIDHex := node.Permission.ParentID.Hex()
			if parent, ok := tree.nodes[parentIDHex]; ok {
				node.Parent = parent
				parent.Children = append(parent.Children, node)
			}
		}
	}

	// 第三遍：計算 PathIDs (從根節點向下遞迴)
	var buildPathIDs func(*PermissionNode, []string)
	buildPathIDs = func(node *PermissionNode, parentPath []string) {
		node.PathIDs = make([]string, len(parentPath))
		copy(node.PathIDs, parentPath)

		// 為子節點建立新路徑 (加入當前節點 ID)
		childPath := append(parentPath, node.Permission.ID.Hex())
		for _, child := range node.Children {
			buildPathIDs(child, childPath)
		}
	}

	// 從所有根節點開始
	for _, root := range tree.roots {
		buildPathIDs(root, []string{})
	}

	return tree
}

// GetNode 取得節點
func (t *PermissionTree) GetNode(id string) *PermissionNode {
	return t.nodes[id]
}

// GetNodeByObjectID 根據 ObjectID 取得節點
func (t *PermissionTree) GetNodeByObjectID(id bson.ObjectID) *PermissionNode {
	return t.nodes[id.Hex()]
}

// GetNodesByName 根據名稱取得節點列表
func (t *PermissionTree) GetNodesByName(name string) []*PermissionNode {
	ids, ok := t.nameIndex[name]
	if !ok {
		return nil
	}

	nodes := make([]*PermissionNode, 0, len(ids))
	for _, id := range ids {
		if node, ok := t.nodes[id]; ok {
			nodes = append(nodes, node)
		}
	}
	return nodes
}

// ExpandPermissions 展開權限 (包含所有父權限)
func (t *PermissionTree) ExpandPermissions(permissions permission.Permissions) (permission.Permissions, error) {
	expanded := make(permission.Permissions)
	visited := make(map[string]bool)

	for name, status := range permissions {
		if status != permission.Open {
			continue
		}

		nodes := t.GetNodesByName(name)
		if len(nodes) == 0 {
			return nil, fmt.Errorf("permission not found: %s", name)
		}

		for _, node := range nodes {
			// 如果是父節點，檢查是否有任何子節點被開啟
			if len(node.Children) > 0 {
				hasActiveChild := false
				for _, child := range node.Children {
					if permissions.HasPermission(child.Permission.Name) {
						hasActiveChild = true
						break
					}
				}
				// 如果沒有任何子節點被開啟，跳過此父節點
				if !hasActiveChild {
					continue
				}
			}

			// 加入此節點
			idHex := node.Permission.ID.Hex()
			if !visited[idHex] {
				expanded.AddPermission(node.Permission.Name)
				visited[idHex] = true
			}

			// 加入所有父節點
			for _, parentID := range node.PathIDs {
				if !visited[parentID] {
					if parentNode := t.GetNode(parentID); parentNode != nil {
						expanded.AddPermission(parentNode.Permission.Name)
						visited[parentID] = true
					}
				}
			}
		}
	}

	return expanded, nil
}

// GetPermissionIDs 取得權限 ID 列表 (包含父權限)
func (t *PermissionTree) GetPermissionIDs(permissions permission.Permissions) ([]bson.ObjectID, error) {
	ids := make([]bson.ObjectID, 0)
	visited := make(map[string]bool)

	for name, status := range permissions {
		if status != permission.Open {
			continue
		}

		nodes := t.GetNodesByName(name)
		if len(nodes) == 0 {
			return nil, fmt.Errorf("permission not found: %s", name)
		}

		for _, node := range nodes {
			// 檢查父節點邏輯
			if len(node.Children) > 0 {
				hasActiveChild := false
				for _, child := range node.Children {
					if permissions.HasPermission(child.Permission.Name) {
						hasActiveChild = true
						break
					}
				}
				if !hasActiveChild {
					continue
				}
			}

			// 加入此節點和所有父節點
			idHex := node.Permission.ID.Hex()
			pathIDs := append(node.PathIDs, idHex)
			for _, id := range pathIDs {
				if !visited[id] {
					oid, _ := bson.ObjectIDFromHex(id)
					ids = append(ids, oid)
					visited[id] = true
				}
			}
		}
	}

	return ids, nil
}

// BuildPermissionsFromIDs 從權限 ID 列表建立權限集合 (包含父權限)
func (t *PermissionTree) BuildPermissionsFromIDs(permissionIDs []bson.ObjectID) permission.Permissions {
	permissions := make(permission.Permissions)
	visited := make(map[string]bool)

	for _, id := range permissionIDs {
		node := t.GetNodeByObjectID(id)
		if node == nil {
			continue
		}

		// 加入此節點
		idHex := node.Permission.ID.Hex()
		if !visited[idHex] {
			permissions.AddPermission(node.Permission.Name)
			visited[idHex] = true
		}

		// 加入所有父節點
		for _, parentID := range node.PathIDs {
			if !visited[parentID] {
				if parentNode := t.GetNode(parentID); parentNode != nil {
					permissions.AddPermission(parentNode.Permission.Name)
					visited[parentID] = true
				}
			}
		}
	}

	return permissions
}

// ToTree 轉換為樹狀結構回應
func (t *PermissionTree) ToTree() []*usecase.PermissionTreeNode {
	result := make([]*usecase.PermissionTreeNode, 0, len(t.roots))

	for _, root := range t.roots {
		result = append(result, t.buildTreeNode(root))
	}

	return result
}

func (t *PermissionTree) buildTreeNode(node *PermissionNode) *usecase.PermissionTreeNode {
	status := permission.Open
	if !node.Permission.State.IsActive() {
		status = permission.Close
	}

	treeNode := &usecase.PermissionTreeNode{
		PermissionResponse: &usecase.PermissionResponse{
			ID:         node.Permission.ID.Hex(),
			ParentID:   node.Permission.ParentID.Hex(),
			Name:       node.Permission.Name,
			HTTPPath:   node.Permission.HTTPPath,
			HTTPMethod: node.Permission.HTTPMethod,
			Status:     status,
			Type:       node.Permission.Type,
		},
		Children: make([]*usecase.PermissionTreeNode, 0, len(node.Children)),
	}

	for _, child := range node.Children {
		treeNode.Children = append(treeNode.Children, t.buildTreeNode(child))
	}

	return treeNode
}

// DetectCircularDependency 檢測循環依賴
func (t *PermissionTree) DetectCircularDependency() error {
	for _, node := range t.nodes {
		visited := make(map[string]bool)
		if err := t.detectCircular(node, visited); err != nil {
			return err
		}
	}
	return nil
}

func (t *PermissionTree) detectCircular(node *PermissionNode, visited map[string]bool) error {
	idHex := node.Permission.ID.Hex()
	if visited[idHex] {
		return fmt.Errorf("circular dependency detected at permission: %s", node.Permission.Name)
	}

	visited[idHex] = true

	if node.Parent != nil {
		return t.detectCircular(node.Parent, visited)
	}

	return nil
}
