# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import logging
from typing import List, Optional

from pypaimon.common.identifier import DEFAULT_MAIN_BRANCH

logger = logging.getLogger(__name__)

BRANCH_PREFIX = "branch-"


class BranchManager:
    """
    Manager for Branch.
    
    This is a base class for managing table branches in Paimon.
    Branches allow multiple lines of development on the same table.
    """

    def create_branch(
        self,
        branch_name: str,
        tag_name: Optional[str] = None,
        ignore_if_exists: bool = False
    ) -> None:
        """
        Create a branch from the current state or from a tag.

        Args:
            branch_name: Name of the branch to create
            tag_name: Optional tag name to create branch from, None for current state
            ignore_if_exists: If true, do nothing when branch already exists;
                            if false, throw exception

        Raises:
            NotImplementedError: Subclasses must implement this method
        """
        raise NotImplementedError("Subclasses must implement create_branch")

    def drop_branch(self, branch_name: str) -> None:
        """
        Drop a branch.
        
        Args:
            branch_name: Name of the branch to drop
        
        Raises:
            NotImplementedError: Subclasses must implement this method
        """
        raise NotImplementedError("Subclasses must implement drop_branch")

    def rename_branch(self, from_branch: str, to_branch: str) -> None:
        """
        Rename a branch.
        
        Args:
            from_branch: Current name of the branch
            to_branch: New name for the branch
        
        Raises:
            NotImplementedError: Subclasses must implement this method
        """
        raise NotImplementedError("Subclasses must implement rename_branch")

    def fast_forward(self, branch_name: str) -> None:
        """
        Fast forward the current branch to the specified branch.
        
        Args:
            branch_name: The branch to fast forward to
        
        Raises:
            NotImplementedError: Subclasses must implement this method
        """
        raise NotImplementedError("Subclasses must implement fast_forward")

    def branches(self) -> List[str]:
        """
        List all branches.
        
        Returns:
            List of branch names
        
        Raises:
            NotImplementedError: Subclasses must implement this method
        """
        raise NotImplementedError("Subclasses must implement branches")

    def branch_exists(self, branch_name: str) -> bool:
        """
        Check if a branch exists.
        
        Args:
            branch_name: Name of the branch to check
        
        Returns:
            True if branch exists, False otherwise
        """
        return branch_name in self.branches()

    @staticmethod
    def branch_path(table_path: str, branch: str) -> str:
        """
        Return the path string of a branch.
        
        Args:
            table_path: The table path
            branch: The branch name
        
        Returns:
            The path to the branch
        """
        if BranchManager.is_main_branch(branch):
            return table_path
        return f"{table_path}/branch/{BRANCH_PREFIX}{branch}"

    @staticmethod
    def normalize_branch(branch: str) -> str:
        """
        Normalize branch name.
        
        Args:
            branch: The branch name to normalize
        
        Returns:
            The normalized branch name
        """
        if not branch or not branch.strip():
            return DEFAULT_MAIN_BRANCH
        return branch.strip()

    @staticmethod
    def is_main_branch(branch: str) -> bool:
        """
        Check if the branch is the main branch.
        
        Args:
            branch: The branch name to check
        
        Returns:
            True if the branch is the main branch, False otherwise
        """
        return branch == DEFAULT_MAIN_BRANCH

    @staticmethod
    def validate_branch(branch_name: str) -> None:
        """
        Validate branch name.
        
        Args:
            branch_name: The branch name to validate
        
        Raises:
            ValueError: If branch name is invalid
        """
        if BranchManager.is_main_branch(branch_name):
            raise ValueError(
                f"Branch name '{branch_name}' is the default branch and cannot be used."
            )
        if not branch_name or not branch_name.strip():
            raise ValueError("Branch name is blank.")
        if branch_name.strip().isdigit():
            raise ValueError(
                f"Branch name cannot be pure numeric string but is '{branch_name}'."
            )

    @staticmethod
    def fast_forward_validate(branch_name: str, current_branch: str) -> None:
        """
        Validate fast-forward parameters.
        
        Args:
            branch_name: The branch to fast forward to
            current_branch: The current branch name
        
        Raises:
            ValueError: If parameters are invalid
        """
        if branch_name == DEFAULT_MAIN_BRANCH:
            raise ValueError(
                f"Branch name '{branch_name}' do not use in fast-forward."
            )
        if not branch_name or not branch_name.strip():
            raise ValueError("Branch name is blank.")
        if branch_name == current_branch:
            raise ValueError(
                f"Fast-forward from the current branch '{current_branch}' is not allowed."
            )
