#!/usr/bin/env python3
# Copyright: 2026, Maximiliano Curia <maxy@debian.org>
#
# License: ISC
#  Permission to use, copy, modify, and/or distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#  .
#  THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
#  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
#  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
#  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#  PERFORMANCE OF THIS SOFTWARE.

"""Core data types for decopy"""

from __future__ import annotations

import dataclasses
import typing as t

from debian.copyright import LicenseParagraph

from ._regex import rex

# Constants for license identification
UNKNOWN = "Unknown"
UNKNOWN_COPYRIGHTED = "UnknownCopyrighted"


@t.final
class License:
    """License representation for copyright files."""

    __slots__ = ("name", "stored")

    licenses: t.ClassVar[dict[str, License]] = {}

    def __init__(self, name: str) -> None:
        self.name: str = name
        self.stored: LicenseParagraph | None = None

    @t.override
    def __str__(self) -> str:
        return self.name

    @staticmethod
    def get(name: str) -> License:
        if name not in License.licenses:
            License.licenses[name] = License(name)

        return License.licenses[name]


@t.final
class YearRange:
    """Year range representation for copyright dates."""

    __slots__ = ("high", "low")

    def __init__(
        self,
        low: str | int | None = None,
        high: str | int | None = None,
    ) -> None:
        low_value = 0 if low is None else int(low)
        high_value = low_value if high is None else int(high)

        if low_value > high_value:
            low_value, high_value = high_value, low_value
        self.low: int = low_value
        self.high: int = high_value

    def __contains__(self, year: str | int) -> bool:
        value = int(year)
        return self.low <= value <= self.high

    def add(self, year: str | int | None) -> YearRange:
        value = int(year if year is not None else 0)
        if not value:
            return self
        if not self.low or value < self.low:
            self.low = value
        if not self.high or self.high < value:
            self.high = value
        return self

    def newer(self, other: YearRange) -> bool:
        if self.high and other.high:
            return other.high > self.high
        return bool(not self.high and other.high)

    def merge(self, other: YearRange) -> YearRange:
        _ = self.add(other.low)
        _ = self.add(other.high)
        return self

    def __bool__(self) -> bool:
        return bool(self.low)

    @t.override
    def __str__(self) -> str:
        if not self.low:
            return ""
        if self.low == self.high:
            return str(self.low)
        return f"{self.low}-{self.high}"


@t.final
class CopyrightHolder:
    """Copyright holder representation for copyright files."""

    __slots__ = ("email", "name", "years")

    def __init__(self, name: str, email: str, years: YearRange | None = None) -> None:
        self.name = name
        self.email = email
        self.years = years if years is not None else YearRange()

    def merge(self, other: CopyrightHolder) -> t.Self:
        if other.name and self.years.newer(other.years):
            self.name = other.name
        if not self.email and other.email:
            self.email = other.email
        _ = self.years.merge(other.years)
        return self

    @property
    def person(self) -> str:
        result = self.name
        if self.name and self.email:
            result += " "
        if self.email:
            result += f"<{self.email}>"
        return result

    @t.override
    def __str__(self) -> str:
        result = str(self.years)
        result += ", " if result else ""
        result += self.person
        return result

    @t.override
    def __repr__(self) -> str:
        return str(self)

    def as_tuple(self) -> tuple[str, str, str]:
        """Return a tuple representation of the CopyrightHolder."""
        years_str = str(self.years) if self.years else ""
        return (self.name, self.email, years_str)


@dataclasses.dataclass
class Options:
    """Options dataclass for decopy configuration."""

    mode: t.Literal["full", "partial"]
    copyright_file: str
    debug: bool
    text: bool
    group_by: t.Literal["license", "copyright"]
    split_on_license: bool
    split_debian: bool
    glob: bool
    progress: bool
    jobs: int
    output: str
    root: str
    files: list[str]
    exclude_fullname_re: rex.Pattern
    exclude_special_re: rex.Pattern
    exclude_file_re: rex.Pattern
    exclude_directory_re: rex.Pattern
    spdx: bool = False
    expand_archives: bool = True
    max_archive_depth: int = 1
    max_archive_member_size: int = 10 * 1024 * 1024
