from pathlib import Path

import re
from functools import total_ordering
from setuptools import __version__ as setuptools_version
from setuptools import find_packages, setup

version = (Path(__file__).parent / "scrapy/VERSION").read_text("ascii").strip()


# PEP 440 pre-release / post-release / dev 映射
_PRE_RELEASE_ORDER = {"a": -3, "alpha": -3, "b": -2, "beta": -2, "rc": -1, "c": -1, "preview": -1}

def _parse_local(local: str):
    """本地版本号：按 . 或 - 分割，数字转 int，字母小写"""
    parts = re.split(r"[.\-]", local)
    result = []
    for p in parts:
        result.append(int(p) if p.isdigit() else p.lower())
    return result

@total_ordering
class Version:
    """
    符合 PEP 440 的版本对象，支持：
      - 正式版：1.2.3
      - pre-release：1.0a1, 1.0b2, 1.0rc1
      - post-release：1.0.post1
      - dev release：1.0.dev1
      - epoch：1!2.0
      - local：1.0+local.1
    """

    _PEP440_RE = re.compile(
        r"""
        ^
        v?
        (?:(?P<epoch>[0-9]+)!)?               # epoch
        (?P<release>[0-9]+(?:\.[0-9]+)*)       # release: 1.2.3
        (?:                                    # pre-release
            [-_\.]?
            (?P<pre_type>a|alpha|b|beta|rc|c|preview)
            [-_\.]?
            (?P<pre_num>[0-9]+)?
        )?
        (?:                                    # post-release
            [-_\.]?
            (?:post|rev|r)
            [-_\.]?
            (?P<post>[0-9]+)?
        )?
        (?:                                    # dev release
            [-_\.]?
            dev
            [-_\.]?
            (?P<dev>[0-9]+)?
        )?
        (?:\+(?P<local>[a-zA-Z0-9][a-zA-Z0-9.\-]*))?  # local
        $
        """,
        re.VERBOSE | re.IGNORECASE,
    )

    def __init__(self, version_str: str):
        self._original = version_str
        m = self._PEP440_RE.match(version_str.strip())
        if not m:
            # 无法解析时退化为字符串比较（legacy behavior）
            self._key = (float("-inf"),)
            self._legacy = version_str
            return
        self._legacy = None

        epoch   = int(m.group("epoch") or 0)
        release = tuple(int(x) for x in m.group("release").split("."))
        pre     = _PRE_RELEASE_ORDER.get((m.group("pre_type") or "").lower())
        pre_num = int(m.group("pre_num") or 0) if pre is not None else None
        post    = int(m.group("post") or 0) if m.group("post") is not None or "post" in version_str.lower() else None
        dev     = int(m.group("dev") or 0) if m.group("dev") is not None or "dev" in version_str.lower() else None
        local   = _parse_local(m.group("local")) if m.group("local") else None

        # 构建排序 key（参考 packaging 库实现）
        # pre-release < 正式版 < post-release；dev < 任何
        if dev is not None and pre is None and post is None:
            pre_key = (-4, dev)        # dev release 最小
        elif pre is not None:
            pre_key = (pre, pre_num)   # a < b < rc < 正式
        elif post is not None:
            pre_key = (1, post)        # post > 正式
        else:
            pre_key = (0, 0)           # 正式版

        # local 版本：有 local > 无 local
        local_key = (1, local) if local else (0, [])

        self._key = (epoch, release, pre_key, local_key)

    def _coerce(self, other):
        if isinstance(other, str):
            return Version(other)
        if isinstance(other, Version):
            return other
        return NotImplemented

    def __eq__(self, other):
        other = self._coerce(other)
        if other is NotImplemented:
            return NotImplemented
        return self._key == other._key

    def __lt__(self, other):
        other = self._coerce(other)
        if other is NotImplemented:
            return NotImplemented
        return self._key < other._key

    def __repr__(self):
        return f"<Version('{self._original}')>"

    def __str__(self):
        return self._original


def parse_version(version_str: str) -> Version:
    """替代 pkg_resources.parse_version，返回可比较的 Version 对象"""
    return Version(version_str)


def has_environment_marker_platform_impl_support():
    """Code extracted from 'pytest/setup.py'
    https://github.com/pytest-dev/pytest/blob/7538680c/setup.py#L31

    The first known release to support environment marker with range operators
    it is 18.5, see:
    https://setuptools.readthedocs.io/en/latest/history.html#id235
    """
    return parse_version(setuptools_version) >= parse_version("18.5")


install_requires = [
    "Twisted>=18.9.0",
    "cryptography>=3.4.6",
    "cssselect>=0.9.1",
    "itemloaders>=1.0.1",
    "parsel>=1.5.0",
    "pyOpenSSL>=21.0.0",
    "queuelib>=1.4.2",
    "service_identity>=18.1.0",
    "w3lib>=1.17.0",
    "zope.interface>=5.1.0",
    "protego>=0.1.15",
    "itemadapter>=0.1.0",
    "setuptools",
    "packaging",
    "tldextract",
    "lxml>=4.3.0",
]
extras_require = {}
cpython_dependencies = [
    "PyDispatcher>=2.0.5",
]
if has_environment_marker_platform_impl_support():
    extras_require[
        ':platform_python_implementation == "CPython"'
    ] = cpython_dependencies
    extras_require[':platform_python_implementation == "PyPy"'] = [
        "PyPyDispatcher>=2.1.0",
    ]
else:
    install_requires.extend(cpython_dependencies)


setup(
    name="Aminer-Scrapy",
    version=version,
    url="https://scrapy.org",
    project_urls={
        "Documentation": "https://docs.scrapy.org/",
        "Source": "https://github.com/scrapy/scrapy",
        "Tracker": "https://github.com/scrapy/scrapy/issues",
    },
    description="A high-level Web Crawling and Web Scraping framework",
    long_description=open("README.rst", encoding="utf-8").read(),
    author="Scrapy developers",
    author_email="pablo@pablohoffman.com",
    maintainer="Pablo Hoffman",
    maintainer_email="pablo@pablohoffman.com",
    license="BSD",
    packages=find_packages(exclude=("tests", "tests.*")),
    include_package_data=True,
    zip_safe=False,
    entry_points={"console_scripts": ["scrapy = scrapy.cmdline:execute"]},
    classifiers=[
        "Framework :: Scrapy",
        "Development Status :: 5 - Production/Stable",
        "Environment :: Console",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: BSD License",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.7",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Programming Language :: Python :: 3.11",
        "Programming Language :: Python :: Implementation :: CPython",
        "Programming Language :: Python :: Implementation :: PyPy",
        "Topic :: Internet :: WWW/HTTP",
        "Topic :: Software Development :: Libraries :: Application Frameworks",
        "Topic :: Software Development :: Libraries :: Python Modules",
    ],
    python_requires=">=3.7",
    install_requires=install_requires,
    extras_require=extras_require,
)
