# pylint: disable=C0115, C0103, C0301

from __future__ import annotations

from enum import Enum
from typing import Annotated, Any, Dict, List, Optional, Type, Union

from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field, NaiveDatetime, RootModel

from vdb.lib.cve_model import cvss_v2, cvss_v3


class UriType(RootModel[AnyUrl]):
    root: Annotated[
        AnyUrl,
        Field(
            description="A universal resource identifier (URI), according to [RFC 3986](https://tools.ietf.org/html/rfc3986)."
        ),
    ]


class UuidType(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="A version 4 (random) universally unique identifier (UUID) as defined by [RFC 4122](https://tools.ietf.org/html/rfc4122#section-4.1.3).",
            pattern="^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$",
        ),
    ]


class ReferenceTags(Enum):
    broken_link = "broken-link"
    customer_entitlement = "customer-entitlement"
    exploit = "exploit"
    government_resource = "government-resource"
    issue_tracking = "issue-tracking"
    mailing_list = "mailing-list"
    mitigation = "mitigation"
    not_applicable = "not-applicable"
    patch = "patch"
    permissions_required = "permissions-required"
    media_coverage = "media-coverage"
    product = "product"
    related = "related"
    release_notes = "release-notes"
    signature = "signature"
    technical_description = "technical-description"
    third_party_advisory = "third-party-advisory"
    vendor_advisory = "vendor-advisory"
    vdb_entry = "vdb-entry"


# Removed patten validation to support a wide range of CVE id
class CveId(RootModel[str]):
    root: Annotated[str, Field(min_length=4, max_length=128)]


class OrgId(RootModel[UuidType]):
    root: Annotated[
        UuidType,
        Field(
            description="A UUID for an organization participating in the CVE program. This UUID can be used to lookup the organization record in the user registry service."
        ),
    ]


class UserId(RootModel[UuidType]):
    root: Annotated[
        UuidType,
        Field(
            description="A UUID for a user participating in the CVE program. This UUID can be used to lookup the user record in the user registry service."
        ),
    ]


class ShortName(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="A 2-32 character name that can be used to complement an organization's UUID.",
            max_length=32,
            min_length=2,
        ),
    ]


class Version(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="A single version of a product, as expressed in its own version numbering scheme.",
            max_length=1024,
            min_length=1,
        ),
    ]


class Status(Enum):
    affected = "affected"
    unaffected = "unaffected"
    unknown = "unknown"


# Removed pattern validation since it wasn't working for go full names
class Cpe(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="Common Platform Enumeration (CPE) Name in either 2.2 or 2.3 format",
            max_length=2048,
            min_length=1,
            title="CPE Name",
        ),
    ]


class Module(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="Name of the affected component, feature, module, sub-component, sub-product, API, command, utility, program, or functionality (optional).",
            min_length=1,
        ),
    ]


class ProgramFile(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="Name or path or location of the affected source code file.",
            max_length=1024,
            min_length=1,
        ),
    ]


class ProgramRoutine(BaseModel):
    name: Annotated[
        str,
        Field(
            description="Name of the affected source code file, function, method, subroutine, or procedure.",
            min_length=1,
        ),
    ]


class Platform(RootModel[str]):
    root: Annotated[
        str,
        Field(
            examples=[
                "iOS",
                "Android",
                "Windows",
                "macOS",
                "x86",
                "ARM",
                "64 bit",
                "Big Endian",
                "iPad",
                "Chromebook",
                "Docker",
                "Model T",
            ],
            max_length=1024,
        ),
    ]


class Change(BaseModel):
    at: Annotated[
        Version, Field(description="The version at which a status change occurs.")
    ]
    status: Annotated[
        Status,
        Field(description="The new status in the range starting at the given version."),
    ]


class Versions(BaseModel):
    version: Annotated[
        Version,
        Field(
            description="The single version being described, or the version at the start of the range. By convention, typically 0 denotes the earliest possible version."
        ),
    ]
    status: Annotated[
        Status,
        Field(
            description="The vulnerability status for the version or range of versions. For a range, the status may be refined by the 'changes' list."
        ),
    ]
    versionType: Annotated[
        Optional[str],
        Field(
            None,
            description="The version numbering system used for specifying the range. This defines the exact semantics of the comparison (less-than) operation on versions, which is required to understand the range itself. 'Custom' indicates that the version type is unspecified and should be avoided whenever possible. It is included primarily for use in conversion of older data files.",
            examples=["custom", "git", "maven", "python", "rpm", "semver"],
            max_length=128,
            min_length=1,
        ),
    ]
    lessThan: Annotated[
        Optional[Version],
        Field(
            None,
            description="The non-inclusive upper limit of the range. This is the least version NOT in the range. The usual version syntax is expanded to allow a pattern to end in an asterisk `(*)`, indicating an arbitrarily large number in the version ordering. For example, `{version: 1.0 lessThan: 1.*}` would describe the entire 1.X branch for most range kinds, and `{version: 2.0, lessThan: *}` describes all versions starting at 2.0, including 3.0, 5.1, and so on. Only one of lessThan and lessThanOrEqual should be specified.",
        ),
    ]
    lessThanOrEqual: Annotated[
        Optional[Version],
        Field(
            None,
            description="The inclusive upper limit of the range. This is the greatest version contained in the range. Only one of lessThan and lessThanOrEqual should be specified. For example, `{version: 1.0, lessThanOrEqual: 1.3}` covers all versions from 1.0 up to and including 1.3.",
        ),
    ]
    changes: Annotated[
        Optional[List[Change]],
        Field(
            None,
            description="A list of status changes that take place during the range. The array should be sorted in increasing order by the 'at' field, according to the versionType, but clients must re-sort the list themselves rather than assume it is sorted.",
            min_length=1,
        ),
    ]


class Versions1(BaseModel):
    version: Annotated[
        Version,
        Field(
            description="The single version being described, or the version at the start of the range. By convention, typically 0 denotes the earliest possible version."
        ),
    ]
    status: Annotated[
        Status,
        Field(
            description="The vulnerability status for the version or range of versions. For a range, the status may be refined by the 'changes' list."
        ),
    ]
    versionType: Annotated[
        str,
        Field(
            description="The version numbering system used for specifying the range. This defines the exact semantics of the comparison (less-than) operation on versions, which is required to understand the range itself. 'Custom' indicates that the version type is unspecified and should be avoided whenever possible. It is included primarily for use in conversion of older data files.",
            examples=["custom", "git", "maven", "python", "rpm", "semver"],
            max_length=128,
            min_length=1,
        ),
    ]
    lessThan: Annotated[
        Version,
        Field(
            description="The non-inclusive upper limit of the range. This is the least version NOT in the range. The usual version syntax is expanded to allow a pattern to end in an asterisk `(*)`, indicating an arbitrarily large number in the version ordering. For example, `{version: 1.0 lessThan: 1.*}` would describe the entire 1.X branch for most range kinds, and `{version: 2.0, lessThan: *}` describes all versions starting at 2.0, including 3.0, 5.1, and so on. Only one of lessThan and lessThanOrEqual should be specified."
        ),
    ]
    lessThanOrEqual: Annotated[
        Optional[Version],
        Field(
            None,
            description="The inclusive upper limit of the range. This is the greatest version contained in the range. Only one of lessThan and lessThanOrEqual should be specified. For example, `{version: 1.0, lessThanOrEqual: 1.3}` covers all versions from 1.0 up to and including 1.3.",
        ),
    ]
    changes: Annotated[
        Optional[List[Change]],
        Field(
            None,
            description="A list of status changes that take place during the range. The array should be sorted in increasing order by the 'at' field, according to the versionType, but clients must re-sort the list themselves rather than assume it is sorted.",
            min_length=1,
        ),
    ]


class Versions2(BaseModel):
    version: Annotated[
        Version,
        Field(
            description="The single version being described, or the version at the start of the range. By convention, typically 0 denotes the earliest possible version."
        ),
    ]
    status: Annotated[
        Status,
        Field(
            description="The vulnerability status for the version or range of versions. For a range, the status may be refined by the 'changes' list."
        ),
    ]
    versionType: Annotated[
        str,
        Field(
            description="The version numbering system used for specifying the range. This defines the exact semantics of the comparison (less-than) operation on versions, which is required to understand the range itself. 'Custom' indicates that the version type is unspecified and should be avoided whenever possible. It is included primarily for use in conversion of older data files.",
            examples=["custom", "git", "maven", "python", "rpm", "semver"],
            max_length=128,
            min_length=1,
        ),
    ]
    lessThan: Annotated[
        Optional[Version],
        Field(
            None,
            description="The non-inclusive upper limit of the range. This is the least version NOT in the range. The usual version syntax is expanded to allow a pattern to end in an asterisk `(*)`, indicating an arbitrarily large number in the version ordering. For example, `{version: 1.0 lessThan: 1.*}` would describe the entire 1.X branch for most range kinds, and `{version: 2.0, lessThan: *}` describes all versions starting at 2.0, including 3.0, 5.1, and so on. Only one of lessThan and lessThanOrEqual should be specified.",
        ),
    ]
    lessThanOrEqual: Annotated[
        Version,
        Field(
            description="The inclusive upper limit of the range. This is the greatest version contained in the range. Only one of lessThan and lessThanOrEqual should be specified. For example, `{version: 1.0, lessThanOrEqual: 1.3}` covers all versions from 1.0 up to and including 1.3."
        ),
    ]
    changes: Annotated[
        Optional[List[Change]],
        Field(
            None,
            description="A list of status changes that take place during the range. The array should be sorted in increasing order by the 'at' field, according to the versionType, but clients must re-sort the list themselves rather than assume it is sorted.",
            min_length=1,
        ),
    ]


class Product(BaseModel):
    vendor: Annotated[
        Optional[str],
        Field(
            None,
            description="Name of the organization, project, community, individual, or user that created or maintains this product or hosted service. Can be 'N/A' if none of those apply. When collectionURL and packageName are used, this field may optionally represent the user or account within the package collection associated with the package.",
            max_length=512,
            min_length=1,
        ),
    ]
    product: Annotated[
        Optional[str],
        Field(
            None,
            description="Name of the affected product.",
            max_length=2048,
            min_length=1,
        ),
    ]
    collectionURL: Annotated[
        Optional[UriType],
        Field(
            None,
            description="URL identifying a package collection (determines the meaning of packageName).",
            examples=[
                "https://access.redhat.com/downloads/content/package-browser",
                "https://addons.mozilla.org",
                "https://addons.thunderbird.net",
                "https://anaconda.org/anaconda/repo",
                "https://app.vagrantup.com/boxes/search",
                "https://apps.apple.com",
                "https://archlinux.org/packages",
                "https://atmospherejs.meteor.com",
                "https://atom.io/packages",
                "https://bitbucket.org",
                "https://bower.io",
                "https://brew.sh/",
                "https://chocolatey.org/packages",
                "https://chrome.google.com/webstore",
                "https://clojars.org",
                "https://cocoapods.org",
                "https://code.dlang.org",
                "https://conan.io/center",
                "https://cpan.org/modules",
                "https://cran.r-project.org",
                "https://crates.io",
                "https://ctan.org/pkg",
                "https://drupal.org",
                "https://exchange.adobe.com",
                "https://forge.puppet.com/modules",
                "https://github.com",
                "https://gitlab.com/explore",
                "https://golang.org/pkg",
                "https://guix.gnu.org/packages",
                "https://hackage.haskell.org",
                "https://helm.sh",
                "https://hub.docker.com",
                "https://juliahub.com",
                "https://lib.haxe.org",
                "https://luarocks.org",
                "https://marketplace.visualstudio.com",
                "https://melpa.org",
                "https://microsoft.com/en-us/store/apps",
                "https://nimble.directory",
                "https://nuget.org/packages",
                "https://opam.ocaml.org/packages",
                "https://openwrt.org/packages/index",
                "https://package.elm-lang.org",
                "https://packagecontrol.io",
                "https://packages.debian.org",
                "https://packages.gentoo.org",
                "https://packagist.org",
                "https://pear.php.net/packages.php",
                "https://pecl.php.net",
                "https://platformio.org/lib",
                "https://play.google.com/store",
                "https://plugins.gradle.org",
                "https://projects.eclipse.org",
                "https://pub.dev",
                "https://pypi.python.org",
                "https://registry.npmjs.org",
                "https://registry.terraform.io",
                "https://repo.hex.pm",
                "https://repo.maven.apache.org/maven2",
                "https://rubygems.org",
                "https://search.nixos.org/packages",
                "https://sourceforge.net",
                "https://wordpress.org/plugins",
            ],
        ),
    ]
    packageName: Annotated[
        Optional[str],
        Field(
            None,
            description="Name or identifier of the affected software package as used in the package collection.",
            max_length=2048,
            min_length=1,
        ),
    ]
    cpes: Annotated[
        Optional[List[Cpe]],
        Field(
            None,
            description='Affected products defined by CPE. This is an array of CPE values (vulnerable and not), we use an array so that we can make multiple statements about the same version and they are separate (if we used a JSON object we\'d essentially be keying on the CPE name and they would have to overlap). Also, this allows things like cveDataVersion or cveDescription to be applied directly to the product entry. This also allows more complex statements such as "Product X between versions 10.2 and 10.8" to be put in a machine-readable format. As well since multiple statements can be used multiple branches of the same product can be defined here.',
        ),
    ]
    modules: Annotated[
        Optional[List[Module]],
        Field(
            None,
            description="A list of the affected components, features, modules, sub-components, sub-products, APIs, commands, utilities, programs, or functionalities (optional).",
        ),
    ]
    programFiles: Annotated[
        Optional[List[ProgramFile]],
        Field(None, description="A list of the affected source code files (optional)."),
    ]
    programRoutines: Annotated[
        Optional[List[ProgramRoutine]],
        Field(
            None,
            description="A list of the affected source code functions, methods, subroutines, or procedures (optional).",
        ),
    ]
    platforms: Annotated[
        Optional[List[Platform]],
        Field(
            None,
            description="List of specific platforms if the vulnerability is only relevant in the context of these platforms (optional). Platforms may include execution environments, operating systems, virtualization technologies, hardware models, or computing architectures. The lack of this field or an empty array implies that the other fields are applicable to all relevant platforms.",
            min_length=1,
            title="Platforms",
        ),
    ]
    repo: Annotated[
        Optional[UriType],
        Field(
            None,
            description="The URL of the source code repository, for informational purposes and/or to resolve git hash version ranges.",
        ),
    ]
    defaultStatus: Annotated[
        Optional[Status],
        Field(
            None,
            description="The default status for versions that are not otherwise listed in the versions list. If not specified, defaultStatus defaults to 'unknown'. Versions or defaultStatus may be omitted, but not both.",
        ),
    ]
    versions: Annotated[
        Optional[List[Union[Versions, Union[Versions1, Versions2]]]],
        Field(
            None,
            description="Set of product versions or version ranges related to the vulnerability. The versions satisfy the CNA Rules [8.1.2 requirement](https://cve.mitre.org/cve/cna/rules.html#section_8-1_cve_entry_information_requirements). Versions or defaultStatus may be omitted, but not both.",
            min_length=1,
        ),
    ]


class DataType(Enum):
    CVE_RECORD = "CVE_RECORD"


class DataVersion(Enum):
    field_5_0 = "5.0"


class State(Enum):
    PUBLISHED = "PUBLISHED"


class CveMetadataPublished(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    cveId: Annotated[
        CveId, Field(description="The CVE identifier that this record pertains to.")
    ]
    assignerOrgId: Annotated[
        OrgId,
        Field(
            description="The UUID for the organization to which the CVE ID was originally assigned. This UUID can be used to lookup the organization record in the user registry service."
        ),
    ]
    assignerShortName: Annotated[
        Optional[ShortName],
        Field(
            None,
            description="The short name for the organization to which the CVE ID was originally assigned.",
        ),
    ]
    requesterUserId: Annotated[
        Optional[UserId],
        Field(None, description="The user that requested the CVE identifier."),
    ]
    dateUpdated: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(None, description="The date/time the record was last updated."),
    ]
    serial: Annotated[
        Optional[int],
        Field(
            None,
            description="The system of record causes this to start at 1, and increment by 1 each time a submission from a data provider changes this CVE Record. The incremented value moves to the Rejected schema upon a PUBLISHED->REJECTED transition, and moves to the Published schema upon a REJECTED->PUBLISHED transition.",
            ge=1,
        ),
    ]
    dateReserved: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="The date/time this CVE ID was reserved in the CVE automation workgroup services system. Disclaimer: This date reflects when the CVE ID was reserved, and does not necessarily indicate when this vulnerability was discovered, shared with the affected vendor, publicly disclosed, or updated in CVE.",
        ),
    ]
    datePublished: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="The date/time the CVE Record was first published in the CVE List.",
        ),
    ]
    state: Annotated[State, Field(description="State of CVE - PUBLISHED, REJECTED.")]


class State1(Enum):
    REJECTED = "REJECTED"


class CveMetadataRejected(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    cveId: Annotated[
        CveId, Field(description="The CVE identifier that this record pertains to.")
    ]
    assignerOrgId: Annotated[
        OrgId,
        Field(
            description="The UUID for the organization to which the CVE ID was originally assigned."
        ),
    ]
    assignerShortName: Annotated[
        Optional[ShortName],
        Field(
            None,
            description="The short name for the organization to which the CVE ID was originally assigned.",
        ),
    ]
    serial: Annotated[
        Optional[int],
        Field(
            None,
            description="The system of record causes this to start at 1, and increment by 1 each time a submission from a data provider changes this CVE Record. The incremented value moves to the Rejected schema upon a PUBLISHED->REJECTED transition, and moves to the Published schema upon a REJECTED->PUBLISHED transition.",
            ge=1,
        ),
    ]
    dateUpdated: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(None, description="The date/time the record was last updated."),
    ]
    datePublished: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="The date/time the CVE Record was first published in the CVE List.",
        ),
    ]
    dateRejected: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(None, description="The date/time the CVE ID was rejected."),
    ]
    state: Annotated[State1, Field(description="State of CVE - PUBLISHED, REJECTED.")]
    dateReserved: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="The date/time this CVE ID was reserved in the CVE automation workgroup services system. Disclaimer: This date reflects when the CVE ID was reserved, and does not necessarily indicate when this vulnerability was discovered, shared with the affected vendor, publicly disclosed, or updated in CVE.",
        ),
    ]


class ProviderMetadata(BaseModel):
    orgId: Annotated[
        OrgId, Field(description="The container provider's organizational UUID.")
    ]
    shortName: Annotated[
        Optional[ShortName],
        Field(None, description="The container provider's organizational short name."),
    ]
    dateUpdated: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="Timestamp to be set by the system of record at time of submission. If dateUpdated is provided to the system of record it will be replaced by the current timestamp at the time of submission.",
        ),
    ]


class Affected(RootModel[List[Product]]):
    root: Annotated[
        List[Product], Field(description="List of affected products.", min_length=1)
    ]


class SupportingMediaItem(BaseModel):
    type: Annotated[
        str,
        Field(
            description="RFC2046 compliant IANA Media type for eg., text/markdown, text/html.",
            examples=[
                "text/markdown",
                "text/html",
                "image/png",
                "image/svg",
                "audio/mp3",
            ],
            max_length=256,
            min_length=1,
            title="Media type",
        ),
    ]
    base64: Annotated[
        Optional[bool],
        Field(
            False,
            description="If true then the value field contains the media data encoded in base64. If false then the value field contains the UTF-8 media content.",
            title="Encoding",
        ),
    ]
    # Removed max_length
    value: Annotated[
        str,
        Field(
            description="Supporting media content. If base64 is true, this field stores base64 encoded data.",
            min_length=1,
        ),
    ]


class Other(BaseModel):
    type: Annotated[
        str,
        Field(
            description="Name of the non-standard impact metrics format used.",
            max_length=128,
            min_length=1,
        ),
    ]
    content: Annotated[
        Dict[str, Any],
        Field(description="JSON object not covered by another metrics format."),
    ]


class Source(BaseModel):
    pass


class Language(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="BCP 47 language code, language-region.",
            pattern="^[A-Za-z]{2,4}([_-][A-Za-z]{4})?([_-]([A-Za-z]{2}|[0-9]{3}))?$",
        ),
    ]


class EnglishLanguage(RootModel[str]):
    root: Annotated[
        str,
        Field(
            description="BCP 47 language code, language-region, required to be English.",
            pattern="^en([_-][A-Za-z]{4})?([_-]([A-Za-z]{2}|[0-9]{3}))?$",
        ),
    ]


class TaxonomyRelation(BaseModel):
    taxonomyId: Annotated[
        str,
        Field(
            description="Identifier of the item in the taxonomy.  Used as the subject of the relationship.",
            max_length=2048,
            min_length=1,
        ),
    ]
    relationshipName: Annotated[
        str,
        Field(
            description="A description of the relationship.",
            max_length=128,
            min_length=1,
        ),
    ]
    relationshipValue: Annotated[
        str,
        Field(
            description="The target of the relationship.  Can be the CVE ID or another taxonomy identifier.",
            max_length=2048,
            min_length=1,
        ),
    ]


class TaxonomyMapping(BaseModel):
    taxonomyName: Annotated[
        str,
        Field(description="The name of the taxonomy.", max_length=128, min_length=1),
    ]
    taxonomyVersion: Annotated[
        Optional[str],
        Field(
            None,
            description="The version of taxonomy the identifiers come from.",
            max_length=128,
            min_length=1,
        ),
    ]
    taxonomyRelations: Annotated[
        List[TaxonomyRelation], Field(description="", min_length=1)
    ]


class TaxonomyMappings(RootModel[List[TaxonomyMapping]]):
    root: Annotated[
        List[TaxonomyMapping],
        Field(
            description="List of taxonomy items related to the vulnerability.",
            min_length=1,
        ),
    ]


class TagExtension(RootModel[str]):
    root: Annotated[str, Field(max_length=128, min_length=2, pattern="^x_.*$")]


class CnaTags(Enum):
    unsupported_when_assigned = "unsupported-when-assigned"
    exclusively_hosted_service = "exclusively-hosted-service"
    disputed = "disputed"


class AdpTags(Enum):
    disputed = "disputed"


class Reference(BaseModel):
    url: Annotated[
        UriType,
        Field(
            description="The uniform resource locator (URL), according to [RFC 3986](https://tools.ietf.org/html/rfc3986#section-1.1.3), that can be used to retrieve the referenced resource."
        ),
    ]
    name: Annotated[
        Optional[str],
        Field(
            None,
            description="User created name for the reference, often the title of the page.",
            max_length=512,
            min_length=1,
        ),
    ]
    tags: Annotated[
        Optional[List[Union[TagExtension, ReferenceTags]]],
        Field(
            None,
            description="An array of one or more tags that describe the resource referenced by 'url'.",
            min_length=1,
        ),
    ]


class Description(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    lang: Language
    value: Annotated[
        str, Field(description="Plain text description.", min_length=1, max_length=4096)
    ]
    supportingMedia: Annotated[
        Optional[List[SupportingMediaItem]],
        Field(
            None,
            description="Supporting media data for the description such as markdown, diagrams, .. (optional). Similar to RFC 2397 each media object has three main parts: media type, media data value, and an optional boolean flag to indicate if the media data is base64 encoded.",
            min_length=1,
            title="Supporting media",
        ),
    ]


class EnglishLanguageDescription(BaseModel):
    lang: EnglishLanguage


class Descriptions(RootModel[List[Description]]):
    root: Annotated[
        List[Description],
        Field(
            description="A list of multi-lingual descriptions of the vulnerability. E.g., [PROBLEMTYPE] in [COMPONENT] in [VENDOR] [PRODUCT] [VERSION] on [PLATFORMS] allows [ATTACKER] to [IMPACT] via [VECTOR]. OR [COMPONENT] in [VENDOR] [PRODUCT] [VERSION] [ROOT CAUSE], which allows [ATTACKER] to [IMPACT] via [VECTOR].",
            min_length=1,
        ),
    ]


class References(RootModel[List[Reference]]):
    root: Annotated[
        List[Reference],
        Field(
            description='This is reference data in the form of URLs or file objects (uuencoded and embedded within the JSON file, exact format to be decided, e.g. we may require a compressed format so the objects require unpacking before they are "dangerous").',
            max_length=512,
            min_length=1,
        ),
    ]


class Impact(BaseModel):
    capecId: Annotated[
        Optional[str],
        Field(
            None,
            description="CAPEC ID that best relates to this impact.",
            max_length=11,
            min_length=7,
            pattern="^CAPEC-[1-9][0-9]{0,4}$",
        ),
    ]
    descriptions: Annotated[
        Descriptions,
        Field(
            description="Prose description of the impact scenario. At a minimum provide the description given by CAPEC."
        ),
    ]


class Impacts(RootModel[List[Impact]]):
    root: Annotated[
        List[Impact],
        Field(description="Collection of impacts of this vulnerability.", min_length=1),
    ]


class Scenario(BaseModel):
    lang: Language
    value: Annotated[
        str,
        Field(
            description="Description of the scenario this metrics object applies to. If no specific scenario is given, GENERAL is used as the default and applies when no more specific metric matches.",
            min_length=1,
        ),
    ]


class Configurations(RootModel[List[Description]]):
    root: Annotated[
        List[Description],
        Field(
            description="Configurations required for exploiting this vulnerability.",
            min_length=1,
        ),
    ]


class Workarounds(RootModel[List[Description]]):
    root: Annotated[
        List[Description],
        Field(
            description="Workarounds and mitigations for this vulnerability.",
            min_length=1,
        ),
    ]


class Solutions(RootModel[List[Description]]):
    root: Annotated[
        List[Description],
        Field(
            description="Information about solutions or remediations available for this vulnerability.",
            min_length=1,
        ),
    ]


class Exploits(RootModel[List[Description]]):
    root: Annotated[
        List[Description],
        Field(
            description="Information about exploits of the vulnerability.", min_length=1
        ),
    ]


class TimelineItem(BaseModel):
    time: Annotated[
        AwareDatetime,
        Field(
            description="Timestamp representing when the event in the timeline occurred. The timestamp format is based on RFC3339 and ISO ISO8601, with an optional timezone. yyyy-MM-ddTHH:mm:ssZZZZ - if the timezone offset is not given, GMT (0000) is assumed."
        ),
    ]
    lang: Annotated[
        Language,
        Field(
            description="The language used in the description of the event. The language field is included so that CVE Records can support translations. The value must be a BCP 47 language code."
        ),
    ]
    value: Annotated[
        str, Field(description="A summary of the event.", min_length=1)
    ]


class Timeline(RootModel[List[TimelineItem]]):
    root: Annotated[
        List[TimelineItem],
        Field(
            description="This is timeline information for significant events about this vulnerability or changes to the CVE Record.",
            min_length=1,
        ),
    ]


class Credit(BaseModel):
    lang: Annotated[
        Language,
        Field(
            description="The language used when describing the credits. The language field is included so that CVE Records can support translations. The value must be a BCP 47 language code."
        ),
    ]
    value: Annotated[str, Field(max_length=4096, min_length=1)]
    user: Annotated[
        Optional[UuidType],
        Field(
            None,
            description="UUID of the user being credited if present in the CVE User Registry (optional). This UUID can be used to lookup the user record in the user registry service.",
        ),
    ]
    type: Annotated[
        Optional[Type],
        Field(
            "finder",
            description="Type or role of the entity being credited (optional). finder: identifies the vulnerability.\nreporter: notifies the vendor of the vulnerability to a CNA.\nanalyst: validates the vulnerability to ensure accuracy or severity.\ncoordinator: facilitates the coordinated response process.\nremediation developer: prepares a code change or other remediation plans.\nremediation reviewer: reviews vulnerability remediation plans or code changes for effectiveness and completeness.\nremediation verifier: tests and verifies the vulnerability or its remediation.\ntool: names of tools used in vulnerability discovery or identification.\nsponsor: supports the vulnerability identification or remediation activities.",
        ),
    ]


class Credits(RootModel[List[Credit]]):
    root: Annotated[
        List[Credit],
        Field(
            description="Statements acknowledging specific people, organizations, or tools recognizing the work done in researching, discovering, remediating or helping with activities related to this CVE.",
            min_length=1,
        ),
    ]


class CnaTagsModel(RootModel[List[Union[TagExtension, CnaTags]]]):
    root: Annotated[
        List[Union[TagExtension, CnaTags]],
        Field(
            description="Tags provided by a CNA describing the CVE Record.",
            min_length=1,
        ),
    ]


class AdpTagsModel(RootModel[List[Union[TagExtension, AdpTags]]]):
    root: Annotated[
        List[Union[TagExtension, AdpTags]],
        Field(
            description="Tags provided by an ADP describing the CVE Record.",
            min_length=1,
        ),
    ]


class CnaRejectedContainer(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    providerMetadata: ProviderMetadata
    rejectedReasons: Annotated[
        Descriptions, Field(description="Reasons for rejecting this CVE Record.")
    ]
    replacedBy: Annotated[
        Optional[List[CveId]],
        Field(
            None,
            description="Contains an array of CVE IDs that this CVE ID was rejected in favor of because this CVE ID was assigned to the vulnerabilities.",
            min_length=1,
        ),
    ]


class Description1(BaseModel):
    lang: Language
    description: Annotated[
        str,
        Field(
            description="Text description of problemType, or title from CWE or OWASP.",
            min_length=1,
        ),
    ]
    cweId: Annotated[
        Optional[str],
        Field(
            None,
            description="CWE ID of the CWE that best describes this problemType entry.",
            max_length=9,
            min_length=5,
            pattern="^CWE-[1-9][0-9]*$",
        ),
    ]
    type: Annotated[
        Optional[str],
        Field(
            None,
            description="Problemtype source, text, OWASP, CWE, etc.,",
            max_length=128,
            min_length=1,
        ),
    ]
    references: Optional[References] = None


class ProblemType(BaseModel):
    descriptions: Annotated[List[Description1], Field(min_length=1)]


class ProblemTypes(RootModel[List[ProblemType]]):
    root: Annotated[
        List[ProblemType],
        Field(
            description="This is problem type information (e.g. CWE identifier). Must contain: At least one entry, can be text, OWASP, CWE, please note that while only one is required you can use more than one (or indeed all three) as long as they are correct). (CNA requirement: [PROBLEMTYPE]).",
            min_length=1,
        ),
    ]


class Metrics1(BaseModel):
    format: Annotated[
        Optional[str],
        Field(
            None,
            description="Name of the scoring format. This provides a bit of future proofing. Additional properties are not prohibited, so this will support the inclusion of proprietary formats. It also provides an easy future conversion mechanism when future score formats become part of the schema. example: cvssV44, format = 'cvssV44', other = cvssV4_4 JSON object. In the future, the other properties can be converted to score properties when they become part of the schema.",
            max_length=64,
            min_length=1,
        ),
    ]
    scenarios: Annotated[
        Optional[List[Scenario]],
        Field(
            None,
            description="Description of the scenarios this metrics object applies to. If no specific scenario is given, GENERAL is used as the default and applies when no more specific metric matches.",
            min_length=1,
        ),
    ]
    cvssV3_1: cvss_v3.Field1
    cvssV3_0: Optional[cvss_v3.Field0] = None
    cvssV2_0: Optional[cvss_v2.Field0] = None
    other: Annotated[
        Optional[Other],
        Field(
            None,
            description="A non-standard impact description, may be prose or JSON block.",
        ),
    ]


class Metrics2(BaseModel):
    format: Annotated[
        Optional[str],
        Field(
            None,
            description="Name of the scoring format. This provides a bit of future proofing. Additional properties are not prohibited, so this will support the inclusion of proprietary formats. It also provides an easy future conversion mechanism when future score formats become part of the schema. example: cvssV44, format = 'cvssV44', other = cvssV4_4 JSON object. In the future, the other properties can be converted to score properties when they become part of the schema.",
            max_length=64,
            min_length=1,
        ),
    ]
    scenarios: Annotated[
        Optional[List[Scenario]],
        Field(
            None,
            description="Description of the scenarios this metrics object applies to. If no specific scenario is given, GENERAL is used as the default and applies when no more specific metric matches.",
            min_length=1,
        ),
    ]
    cvssV3_1: Optional[cvss_v3.Field1] = None
    cvssV3_0: cvss_v3.Field0
    cvssV2_0: Optional[cvss_v2.Field0] = None
    other: Annotated[
        Optional[Other],
        Field(
            None,
            description="A non-standard impact description, may be prose or JSON block.",
        ),
    ]


class Metrics3(BaseModel):
    format: Annotated[
        Optional[str],
        Field(
            None,
            description="Name of the scoring format. This provides a bit of future proofing. Additional properties are not prohibited, so this will support the inclusion of proprietary formats. It also provides an easy future conversion mechanism when future score formats become part of the schema. example: cvssV44, format = 'cvssV44', other = cvssV4_4 JSON object. In the future, the other properties can be converted to score properties when they become part of the schema.",
            max_length=64,
            min_length=1,
        ),
    ]
    scenarios: Annotated[
        Optional[List[Scenario]],
        Field(
            None,
            description="Description of the scenarios this metrics object applies to. If no specific scenario is given, GENERAL is used as the default and applies when no more specific metric matches.",
            min_length=1,
        ),
    ]
    cvssV3_1: Optional[cvss_v3.Field1] = None
    cvssV3_0: Optional[cvss_v3.Field0] = None
    cvssV2_0: cvss_v2.Field0
    other: Annotated[
        Optional[Other],
        Field(
            None,
            description="A non-standard impact description, may be prose or JSON block.",
        ),
    ]


class Metrics4(BaseModel):
    format: Annotated[
        Optional[str],
        Field(
            None,
            description="Name of the scoring format. This provides a bit of future proofing. Additional properties are not prohibited, so this will support the inclusion of proprietary formats. It also provides an easy future conversion mechanism when future score formats become part of the schema. example: cvssV44, format = 'cvssV44', other = cvssV4_4 JSON object. In the future, the other properties can be converted to score properties when they become part of the schema.",
            max_length=64,
            min_length=1,
        ),
    ]
    scenarios: Annotated[
        Optional[List[Scenario]],
        Field(
            None,
            description="Description of the scenarios this metrics object applies to. If no specific scenario is given, GENERAL is used as the default and applies when no more specific metric matches.",
            min_length=1,
        ),
    ]
    cvssV3_1: Optional[cvss_v3.Field1] = None
    cvssV3_0: Optional[cvss_v3.Field0] = None
    cvssV2_0: Optional[cvss_v2.Field0] = None
    other: Annotated[
        Other,
        Field(
            description="A non-standard impact description, may be prose or JSON block."
        ),
    ]


class Metrics(RootModel[List[Union[Metrics1, Metrics2, Metrics3, Metrics4]]]):
    root: Annotated[
        List[Union[Metrics1, Metrics2, Metrics3, Metrics4]],
        Field(
            description="Collection of impact scores with attribution.", min_length=1
        ),
    ]


class Containers1(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    cna: CnaRejectedContainer


class CVE2(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    dataType: DataType
    dataVersion: DataVersion
    cveMetadata: CveMetadataRejected
    containers: Annotated[
        Containers1,
        Field(
            description="A set of structures (called containers) used to store vulnerability information related to a specific CVE ID provided by a specific organization participating in the CVE program. Each container includes information provided by a different source.\n\nAt minimum, a 'cna' container containing the vulnerability information provided by the CNA who initially assigned the CVE ID must be included.\n\nThere can only be one 'cna' container, as there can only be one assigning CNA."
        ),
    ]


class CnaPublishedContainer(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    providerMetadata: ProviderMetadata
    dateAssigned: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="The date/time this CVE ID was associated with a vulnerability by a CNA.",
        ),
    ]
    datePublic: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="If known, the date/time the vulnerability was disclosed publicly.",
        ),
    ]
    title: Annotated[
        Optional[str],
        Field(
            None,
            description="A title, headline, or a brief phrase summarizing the CVE record. Eg., Buffer overflow in Example Soft.",
            max_length=256,
            min_length=1,
        ),
    ]
    descriptions: Descriptions
    affected: Affected
    problemTypes: Optional[ProblemTypes] = None
    references: Optional[References] = None
    impacts: Optional[Impacts] = None
    metrics: Optional[Metrics] = None
    configurations: Optional[Configurations] = None
    workarounds: Optional[Workarounds] = None
    solutions: Optional[Solutions] = None
    exploits: Optional[Exploits] = None
    timeline: Optional[Timeline] = None
    credits: Optional[Credits] = None
    source: Optional[Source] = None
    tags: Optional[CnaTagsModel] = None
    taxonomyMappings: Optional[TaxonomyMappings] = None


CnaPublishedContainer.model_rebuild()


class AdpContainer(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    providerMetadata: ProviderMetadata
    datePublic: Annotated[
        Optional[AwareDatetime | NaiveDatetime],
        Field(
            None,
            description="If known, the date/time the vulnerability was disclosed publicly.",
        ),
    ]
    title: Annotated[
        Optional[str],
        Field(
            None,
            description="A title, headline, or a brief phrase summarizing the information in an ADP container.",
            max_length=256,
            min_length=1,
        ),
    ]
    descriptions: Optional[Descriptions] = None
    affected: Optional[Affected] = None
    problemTypes: Optional[ProblemTypes] = None
    references: Optional[References] = None
    impacts: Optional[Impacts] = None
    metrics: Optional[Metrics] = None
    configurations: Optional[Configurations] = None
    workarounds: Optional[Workarounds] = None
    solutions: Optional[Solutions] = None
    exploits: Optional[Exploits] = None
    timeline: Optional[Timeline] = None
    credits: Optional[Credits] = None
    source: Optional[Source] = None
    tags: Optional[AdpTagsModel] = None
    taxonomyMappings: Optional[TaxonomyMappings] = None


class Containers(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    cna: Optional[CnaPublishedContainer]
    adp: Annotated[Optional[List[AdpContainer]], Field(None, min_length=1)]


class CVE1(BaseModel):
    model_config = ConfigDict(
        extra="forbid",
    )
    dataType: DataType
    dataVersion: DataVersion
    cveMetadata: CveMetadataPublished
    containers: Annotated[
        Containers,
        Field(
            description="A set of structures (called containers) used to store vulnerability information related to a specific CVE ID provided by a specific organization participating in the CVE program. Each container includes information provided by a different source.\n\nAt a minimum, a 'cna' container containing the vulnerability information provided by the CNA who initially assigned the CVE ID must be included.\n\nThere can only be one 'cna' container, as there can only be one assigning CNA. However, there can be multiple 'adp' containers, allowing multiple organizations participating in the CVE program to add additional information related to the vulnerability. For the most part, the 'cna' and 'adp' containers contain the same properties. The main differences are the source of the information. The 'cna' container requires the CNA to include certain fields, while the 'adp' container does not."
        ),
    ]


class CVE(RootModel[Union[CVE1, CVE2]]):
    root: Annotated[
        Union[CVE1, CVE2],
        Field(
            description="cve-schema specifies the CVE JSON record format. This is the blueprint for a rich set of JSON data that can be submitted by CVE Numbering Authorities (CNAs) and Authorized Data Publishers (ADPs) to describe a CVE Record. Some examples of CVE Record data include CVE ID number, affected product(s), affected version(s), and public references. While those specific items are required when assigning a CVE, there are many other optional data in the schema that can be used to enrich CVE Records for community benefit. Learn more about the CVE program at [the official website](https://cve.mitre.org). This CVE JSON record format is defined using JSON Schema. Learn more about JSON Schema [here](https://json-schema.org/).",
            title="CVE JSON record format",
        ),
    ]
