from __future__ import annotations

from typing import TYPE_CHECKING, Callable

if TYPE_CHECKING:
    from hatchling.metadata.core import ProjectMetadata

DEFAULT_METADATA_VERSION = '2.1'


def get_core_metadata_constructors() -> dict[str, Callable]:
    """
    https://packaging.python.org/specifications/core-metadata/
    """
    return {
        '1.2': construct_metadata_file_1_2,
        '2.1': construct_metadata_file_2_1,
        '2.2': construct_metadata_file_2_2,
        '2.3': construct_metadata_file_2_3,
    }


def construct_metadata_file_1_2(metadata: ProjectMetadata, extra_dependencies: tuple[str] | None = None) -> str:
    """
    https://peps.python.org/pep-0345/
    """
    metadata_file = 'Metadata-Version: 1.2\n'
    metadata_file += f'Name: {metadata.core.raw_name}\n'
    metadata_file += f'Version: {metadata.version}\n'

    if metadata.core.description:
        metadata_file += f'Summary: {metadata.core.description}\n'

    if metadata.core.urls:
        for label, url in metadata.core.urls.items():
            metadata_file += f'Project-URL: {label}, {url}\n'

    authors_data = metadata.core.authors_data
    if authors_data['name']:
        metadata_file += f"Author: {', '.join(authors_data['name'])}\n"
    if authors_data['email']:
        metadata_file += f"Author-email: {', '.join(authors_data['email'])}\n"

    maintainers_data = metadata.core.maintainers_data
    if maintainers_data['name']:
        metadata_file += f"Maintainer: {', '.join(maintainers_data['name'])}\n"
    if maintainers_data['email']:
        metadata_file += f"Maintainer-email: {', '.join(maintainers_data['email'])}\n"

    if metadata.core.license:
        license_start = 'License: '
        indent = ' ' * (len(license_start) - 1)
        metadata_file += license_start

        for i, line in enumerate(metadata.core.license.splitlines()):
            if i == 0:
                metadata_file += f'{line}\n'
            else:
                metadata_file += f'{indent}{line}\n'

    if metadata.core.keywords:
        metadata_file += f"Keywords: {','.join(metadata.core.keywords)}\n"

    if metadata.core.classifiers:
        for classifier in metadata.core.classifiers:
            metadata_file += f'Classifier: {classifier}\n'

    if metadata.core.requires_python:
        metadata_file += f'Requires-Python: {metadata.core.requires_python}\n'

    if metadata.core.dependencies:
        for dependency in metadata.core.dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if extra_dependencies:
        for dependency in extra_dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    return metadata_file


def construct_metadata_file_2_1(metadata: ProjectMetadata, extra_dependencies: tuple[str] | None = None) -> str:
    """
    https://peps.python.org/pep-0566/
    """
    metadata_file = 'Metadata-Version: 2.1\n'
    metadata_file += f'Name: {metadata.core.raw_name}\n'
    metadata_file += f'Version: {metadata.version}\n'

    if metadata.core.description:
        metadata_file += f'Summary: {metadata.core.description}\n'

    if metadata.core.urls:
        for label, url in metadata.core.urls.items():
            metadata_file += f'Project-URL: {label}, {url}\n'

    authors_data = metadata.core.authors_data
    if authors_data['name']:
        metadata_file += f"Author: {', '.join(authors_data['name'])}\n"
    if authors_data['email']:
        metadata_file += f"Author-email: {', '.join(authors_data['email'])}\n"

    maintainers_data = metadata.core.maintainers_data
    if maintainers_data['name']:
        metadata_file += f"Maintainer: {', '.join(maintainers_data['name'])}\n"
    if maintainers_data['email']:
        metadata_file += f"Maintainer-email: {', '.join(maintainers_data['email'])}\n"

    if metadata.core.license:
        license_start = 'License: '
        indent = ' ' * (len(license_start) - 1)
        metadata_file += license_start

        for i, line in enumerate(metadata.core.license.splitlines()):
            if i == 0:
                metadata_file += f'{line}\n'
            else:
                metadata_file += f'{indent}{line}\n'

    if metadata.core.license_expression:
        metadata_file += f'License-Expression: {metadata.core.license_expression}\n'

    if metadata.core.license_files:
        for license_file in metadata.core.license_files:
            metadata_file += f'License-File: {license_file}\n'

    if metadata.core.keywords:
        metadata_file += f"Keywords: {','.join(metadata.core.keywords)}\n"

    if metadata.core.classifiers:
        for classifier in metadata.core.classifiers:
            metadata_file += f'Classifier: {classifier}\n'

    if metadata.core.requires_python:
        metadata_file += f'Requires-Python: {metadata.core.requires_python}\n'

    if metadata.core.dependencies:
        for dependency in metadata.core.dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if extra_dependencies:
        for dependency in extra_dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if metadata.core.optional_dependencies:
        for option, dependencies in metadata.core.optional_dependencies.items():
            metadata_file += f'Provides-Extra: {option}\n'
            for dependency in dependencies:
                if ';' in dependency:
                    dep_name, dep_env_marker = dependency.split(';', maxsplit=1)
                    metadata_file += f'Requires-Dist: {dep_name}; ({dep_env_marker.strip()}) and extra == {option!r}\n'
                elif '@ ' in dependency:
                    metadata_file += f'Requires-Dist: {dependency} ; extra == {option!r}\n'
                else:
                    metadata_file += f'Requires-Dist: {dependency}; extra == {option!r}\n'

    if metadata.core.readme:
        metadata_file += f'Description-Content-Type: {metadata.core.readme_content_type}\n'
        metadata_file += f'\n{metadata.core.readme}'

    return metadata_file


def construct_metadata_file_2_2(metadata: ProjectMetadata, extra_dependencies: tuple[str] | None = None) -> str:
    """
    https://peps.python.org/pep-0643/
    """
    metadata_file = 'Metadata-Version: 2.2\n'
    metadata_file += f'Name: {metadata.core.raw_name}\n'
    metadata_file += f'Version: {metadata.version}\n'

    if metadata.core.description:
        metadata_file += f'Summary: {metadata.core.description}\n'

    if metadata.core.urls:
        for label, url in metadata.core.urls.items():
            metadata_file += f'Project-URL: {label}, {url}\n'

    authors_data = metadata.core.authors_data
    if authors_data['name']:
        metadata_file += f"Author: {', '.join(authors_data['name'])}\n"
    if authors_data['email']:
        metadata_file += f"Author-email: {', '.join(authors_data['email'])}\n"

    maintainers_data = metadata.core.maintainers_data
    if maintainers_data['name']:
        metadata_file += f"Maintainer: {', '.join(maintainers_data['name'])}\n"
    if maintainers_data['email']:
        metadata_file += f"Maintainer-email: {', '.join(maintainers_data['email'])}\n"

    if metadata.core.license:
        license_start = 'License: '
        indent = ' ' * (len(license_start) - 1)
        metadata_file += license_start

        for i, line in enumerate(metadata.core.license.splitlines()):
            if i == 0:
                metadata_file += f'{line}\n'
            else:
                metadata_file += f'{indent}{line}\n'

    if metadata.core.license_expression:
        metadata_file += f'License-Expression: {metadata.core.license_expression}\n'

    if metadata.core.license_files:
        for license_file in metadata.core.license_files:
            metadata_file += f'License-File: {license_file}\n'

    if metadata.core.keywords:
        metadata_file += f"Keywords: {','.join(metadata.core.keywords)}\n"

    if metadata.core.classifiers:
        for classifier in metadata.core.classifiers:
            metadata_file += f'Classifier: {classifier}\n'

    if metadata.core.requires_python:
        metadata_file += f'Requires-Python: {metadata.core.requires_python}\n'

    if metadata.core.dependencies:
        for dependency in metadata.core.dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if extra_dependencies:
        for dependency in extra_dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if metadata.core.optional_dependencies:
        for option, dependencies in metadata.core.optional_dependencies.items():
            metadata_file += f'Provides-Extra: {option}\n'
            for dependency in dependencies:
                if ';' in dependency:
                    dep_name, dep_env_marker = dependency.split(';', maxsplit=1)
                    metadata_file += f'Requires-Dist: {dep_name}; ({dep_env_marker.strip()}) and extra == {option!r}\n'
                elif '@ ' in dependency:
                    metadata_file += f'Requires-Dist: {dependency} ; extra == {option!r}\n'
                else:
                    metadata_file += f'Requires-Dist: {dependency}; extra == {option!r}\n'

    if metadata.core.readme:
        metadata_file += f'Description-Content-Type: {metadata.core.readme_content_type}\n'
        metadata_file += f'\n{metadata.core.readme}'

    return metadata_file


def construct_metadata_file_2_3(metadata: ProjectMetadata, extra_dependencies: tuple[str] | None = None) -> str:
    """
    https://peps.python.org/pep-0639/
    """
    metadata_file = 'Metadata-Version: 2.3\n'
    metadata_file += f'Name: {metadata.core.raw_name}\n'
    metadata_file += f'Version: {metadata.version}\n'

    if metadata.core.description:
        metadata_file += f'Summary: {metadata.core.description}\n'

    if metadata.core.urls:
        for label, url in metadata.core.urls.items():
            metadata_file += f'Project-URL: {label}, {url}\n'

    authors_data = metadata.core.authors_data
    if authors_data['name']:
        metadata_file += f"Author: {', '.join(authors_data['name'])}\n"
    if authors_data['email']:
        metadata_file += f"Author-email: {', '.join(authors_data['email'])}\n"

    maintainers_data = metadata.core.maintainers_data
    if maintainers_data['name']:
        metadata_file += f"Maintainer: {', '.join(maintainers_data['name'])}\n"
    if maintainers_data['email']:
        metadata_file += f"Maintainer-email: {', '.join(maintainers_data['email'])}\n"

    if metadata.core.license_expression:
        metadata_file += f'License-Expression: {metadata.core.license_expression}\n'

    if metadata.core.license_files:
        for license_file in metadata.core.license_files:
            metadata_file += f'License-File: {license_file}\n'

    if metadata.core.keywords:
        metadata_file += f"Keywords: {','.join(metadata.core.keywords)}\n"

    if metadata.core.classifiers:
        for classifier in metadata.core.classifiers:
            metadata_file += f'Classifier: {classifier}\n'

    if metadata.core.requires_python:
        metadata_file += f'Requires-Python: {metadata.core.requires_python}\n'

    if metadata.core.dependencies:
        for dependency in metadata.core.dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if extra_dependencies:
        for dependency in extra_dependencies:
            metadata_file += f'Requires-Dist: {dependency}\n'

    if metadata.core.optional_dependencies:
        for option, dependencies in metadata.core.optional_dependencies.items():
            metadata_file += f'Provides-Extra: {option}\n'
            for dependency in dependencies:
                if ';' in dependency:
                    dep_name, dep_env_marker = dependency.split(';', maxsplit=1)
                    metadata_file += f'Requires-Dist: {dep_name}; ({dep_env_marker.strip()}) and extra == {option!r}\n'
                elif '@ ' in dependency:
                    metadata_file += f'Requires-Dist: {dependency} ; extra == {option!r}\n'
                else:
                    metadata_file += f'Requires-Dist: {dependency}; extra == {option!r}\n'

    if metadata.core.readme:
        metadata_file += f'Description-Content-Type: {metadata.core.readme_content_type}\n'
        metadata_file += f'\n{metadata.core.readme}'

    return metadata_file
