# coding: utf-8

"""
    The Jira Cloud platform REST API

    Jira Cloud platform REST API documentation

    The version of the OpenAPI document: 1001.0.0-SNAPSHOT-7ce0ee67a52d004425175cea962ad1c1c7200181
    Contact: ecosystem@atlassian.com
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr, field_validator
from typing import Any, ClassVar, Dict, List, Optional
from jira_client.models.avatar_urls_bean import AvatarUrlsBean
from jira_client.models.hierarchy import Hierarchy
from jira_client.models.issue_type_details import IssueTypeDetails
from jira_client.models.project_category import ProjectCategory
from jira_client.models.project_component import ProjectComponent
from jira_client.models.project_insight import ProjectInsight
from jira_client.models.project_landing_page_info import ProjectLandingPageInfo
from jira_client.models.project_permissions import ProjectPermissions
from jira_client.models.user import User
from jira_client.models.version import Version
from typing import Optional, Set
from typing_extensions import Self

class Project(BaseModel):
    """
    Details about a project.
    """ # noqa: E501
    archived: Optional[StrictBool] = Field(default=None, description="Whether the project is archived.")
    archived_by: Optional[User] = Field(default=None, description="The user who archived the project.", alias="archivedBy")
    archived_date: Optional[datetime] = Field(default=None, description="The date when the project was archived.", alias="archivedDate")
    assignee_type: Optional[StrictStr] = Field(default=None, description="The default assignee when creating issues for this project.", alias="assigneeType")
    avatar_urls: Optional[AvatarUrlsBean] = Field(default=None, description="The URLs of the project's avatars.", alias="avatarUrls")
    components: Optional[List[ProjectComponent]] = Field(default=None, description="List of the components contained in the project.")
    deleted: Optional[StrictBool] = Field(default=None, description="Whether the project is marked as deleted.")
    deleted_by: Optional[User] = Field(default=None, description="The user who marked the project as deleted.", alias="deletedBy")
    deleted_date: Optional[datetime] = Field(default=None, description="The date when the project was marked as deleted.", alias="deletedDate")
    description: Optional[StrictStr] = Field(default=None, description="A brief description of the project.")
    email: Optional[StrictStr] = Field(default=None, description="An email address associated with the project.")
    expand: Optional[StrictStr] = Field(default=None, description="Expand options that include additional project details in the response.")
    favourite: Optional[StrictBool] = Field(default=None, description="Whether the project is selected as a favorite.")
    id: Optional[StrictStr] = Field(default=None, description="The ID of the project.")
    insight: Optional[ProjectInsight] = Field(default=None, description="Insights about the project.")
    is_private: Optional[StrictBool] = Field(default=None, description="Whether the project is private from the user's perspective. This means the user can't see the project or any associated issues.", alias="isPrivate")
    issue_type_hierarchy: Optional[Hierarchy] = Field(default=None, description="The issue type hierarchy for the project.", alias="issueTypeHierarchy")
    issue_types: Optional[List[IssueTypeDetails]] = Field(default=None, description="List of the issue types available in the project.", alias="issueTypes")
    key: Optional[StrictStr] = Field(default=None, description="The key of the project.")
    landing_page_info: Optional[ProjectLandingPageInfo] = Field(default=None, description="The project landing page info.", alias="landingPageInfo")
    lead: Optional[User] = Field(default=None, description="The username of the project lead.")
    name: Optional[StrictStr] = Field(default=None, description="The name of the project.")
    permissions: Optional[ProjectPermissions] = Field(default=None, description="User permissions on the project")
    project_category: Optional[ProjectCategory] = Field(default=None, description="The category the project belongs to.", alias="projectCategory")
    project_type_key: Optional[StrictStr] = Field(default=None, description="The [project type](https://confluence.atlassian.com/x/GwiiLQ#Jiraapplicationsoverview-Productfeaturesandprojecttypes) of the project.", alias="projectTypeKey")
    properties: Optional[Dict[str, Any]] = Field(default=None, description="Map of project properties")
    retention_till_date: Optional[datetime] = Field(default=None, description="The date when the project is deleted permanently.", alias="retentionTillDate")
    roles: Optional[Dict[str, StrictStr]] = Field(default=None, description="The name and self URL for each role defined in the project. For more information, see [Create project role](#api-rest-api-3-role-post).")
    var_self: Optional[StrictStr] = Field(default=None, description="The URL of the project details.", alias="self")
    simplified: Optional[StrictBool] = Field(default=None, description="Whether the project is simplified.")
    style: Optional[StrictStr] = Field(default=None, description="The type of the project.")
    url: Optional[StrictStr] = Field(default=None, description="A link to information about this project, such as project documentation.")
    uuid: Optional[StrictStr] = Field(default=None, description="Unique ID for next-gen projects.")
    versions: Optional[List[Version]] = Field(default=None, description="The versions defined in the project. For more information, see [Create version](#api-rest-api-3-version-post).")
    __properties: ClassVar[List[str]] = ["archived", "archivedBy", "archivedDate", "assigneeType", "avatarUrls", "components", "deleted", "deletedBy", "deletedDate", "description", "email", "expand", "favourite", "id", "insight", "isPrivate", "issueTypeHierarchy", "issueTypes", "key", "landingPageInfo", "lead", "name", "permissions", "projectCategory", "projectTypeKey", "properties", "retentionTillDate", "roles", "self", "simplified", "style", "url", "uuid", "versions"]

    @field_validator('assignee_type')
    def assignee_type_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['PROJECT_LEAD', 'UNASSIGNED']):
            raise ValueError("must be one of enum values ('PROJECT_LEAD', 'UNASSIGNED')")
        return value

    @field_validator('project_type_key')
    def project_type_key_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['software', 'service_desk', 'business', 'product_discovery']):
            raise ValueError("must be one of enum values ('software', 'service_desk', 'business', 'product_discovery')")
        return value

    @field_validator('style')
    def style_validate_enum(cls, value):
        """Validates the enum"""
        if value is None:
            return value

        if value not in set(['classic', 'next-gen']):
            raise ValueError("must be one of enum values ('classic', 'next-gen')")
        return value

    model_config = ConfigDict(
        populate_by_name=True,
        validate_assignment=True,
        protected_namespaces=(),
    )


    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of Project from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        * OpenAPI `readOnly` fields are excluded.
        """
        excluded_fields: Set[str] = set([
            "archived",
            "archived_by",
            "archived_date",
            "assignee_type",
            "avatar_urls",
            "components",
            "deleted",
            "deleted_by",
            "deleted_date",
            "description",
            "expand",
            "insight",
            "is_private",
            "issue_type_hierarchy",
            "issue_types",
            "key",
            "landing_page_info",
            "lead",
            "name",
            "permissions",
            "project_category",
            "project_type_key",
            "properties",
            "retention_till_date",
            "roles",
            "var_self",
            "simplified",
            "style",
            "url",
            "uuid",
            "versions",
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of archived_by
        if self.archived_by:
            _dict['archivedBy'] = self.archived_by.to_dict()
        # override the default output from pydantic by calling `to_dict()` of avatar_urls
        if self.avatar_urls:
            _dict['avatarUrls'] = self.avatar_urls.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in components (list)
        _items = []
        if self.components:
            for _item_components in self.components:
                if _item_components:
                    _items.append(_item_components.to_dict())
            _dict['components'] = _items
        # override the default output from pydantic by calling `to_dict()` of deleted_by
        if self.deleted_by:
            _dict['deletedBy'] = self.deleted_by.to_dict()
        # override the default output from pydantic by calling `to_dict()` of insight
        if self.insight:
            _dict['insight'] = self.insight.to_dict()
        # override the default output from pydantic by calling `to_dict()` of issue_type_hierarchy
        if self.issue_type_hierarchy:
            _dict['issueTypeHierarchy'] = self.issue_type_hierarchy.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in issue_types (list)
        _items = []
        if self.issue_types:
            for _item_issue_types in self.issue_types:
                if _item_issue_types:
                    _items.append(_item_issue_types.to_dict())
            _dict['issueTypes'] = _items
        # override the default output from pydantic by calling `to_dict()` of landing_page_info
        if self.landing_page_info:
            _dict['landingPageInfo'] = self.landing_page_info.to_dict()
        # override the default output from pydantic by calling `to_dict()` of lead
        if self.lead:
            _dict['lead'] = self.lead.to_dict()
        # override the default output from pydantic by calling `to_dict()` of permissions
        if self.permissions:
            _dict['permissions'] = self.permissions.to_dict()
        # override the default output from pydantic by calling `to_dict()` of project_category
        if self.project_category:
            _dict['projectCategory'] = self.project_category.to_dict()
        # override the default output from pydantic by calling `to_dict()` of each item in versions (list)
        _items = []
        if self.versions:
            for _item_versions in self.versions:
                if _item_versions:
                    _items.append(_item_versions.to_dict())
            _dict['versions'] = _items
        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of Project from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate({
            "archived": obj.get("archived"),
            "archivedBy": User.from_dict(obj["archivedBy"]) if obj.get("archivedBy") is not None else None,
            "archivedDate": obj.get("archivedDate"),
            "assigneeType": obj.get("assigneeType"),
            "avatarUrls": AvatarUrlsBean.from_dict(obj["avatarUrls"]) if obj.get("avatarUrls") is not None else None,
            "components": [ProjectComponent.from_dict(_item) for _item in obj["components"]] if obj.get("components") is not None else None,
            "deleted": obj.get("deleted"),
            "deletedBy": User.from_dict(obj["deletedBy"]) if obj.get("deletedBy") is not None else None,
            "deletedDate": obj.get("deletedDate"),
            "description": obj.get("description"),
            "email": obj.get("email"),
            "expand": obj.get("expand"),
            "favourite": obj.get("favourite"),
            "id": obj.get("id"),
            "insight": ProjectInsight.from_dict(obj["insight"]) if obj.get("insight") is not None else None,
            "isPrivate": obj.get("isPrivate"),
            "issueTypeHierarchy": Hierarchy.from_dict(obj["issueTypeHierarchy"]) if obj.get("issueTypeHierarchy") is not None else None,
            "issueTypes": [IssueTypeDetails.from_dict(_item) for _item in obj["issueTypes"]] if obj.get("issueTypes") is not None else None,
            "key": obj.get("key"),
            "landingPageInfo": ProjectLandingPageInfo.from_dict(obj["landingPageInfo"]) if obj.get("landingPageInfo") is not None else None,
            "lead": User.from_dict(obj["lead"]) if obj.get("lead") is not None else None,
            "name": obj.get("name"),
            "permissions": ProjectPermissions.from_dict(obj["permissions"]) if obj.get("permissions") is not None else None,
            "projectCategory": ProjectCategory.from_dict(obj["projectCategory"]) if obj.get("projectCategory") is not None else None,
            "projectTypeKey": obj.get("projectTypeKey"),
            "properties": obj.get("properties"),
            "retentionTillDate": obj.get("retentionTillDate"),
            "roles": obj.get("roles"),
            "self": obj.get("self"),
            "simplified": obj.get("simplified"),
            "style": obj.get("style"),
            "url": obj.get("url"),
            "uuid": obj.get("uuid"),
            "versions": [Version.from_dict(_item) for _item in obj["versions"]] if obj.get("versions") is not None else None
        })
        return _obj
