"""Type definitions for zaira."""

from dataclasses import dataclass
from typing import Any, TypedDict


# === Dataclasses (internal structures) ===


@dataclass
class Board:
    """Jira board information."""

    id: int
    name: str
    type: str
    location: str


@dataclass
class Sprint:
    """Jira sprint information."""

    id: int
    name: str
    state: str


@dataclass
class Comment:
    """Jira comment."""

    author: str
    created: str
    body: str


@dataclass
class Worklog:
    """Jira worklog entry."""

    author: str
    time_spent: str
    started: str
    comment: str | None


@dataclass
class Dashboard:
    """Jira dashboard information."""

    id: int
    name: str
    description: str
    owner: str
    view_url: str
    is_favourite: bool


@dataclass
class DashboardGadget:
    """Jira dashboard gadget/item."""

    id: str
    title: str
    gadget_type: str
    position: tuple[int, int]  # (row, column)
    filter_id: str | None = None
    filter_name: str | None = None
    jql: str | None = None


# === TypedDicts (JSON/config structures) ===


class ParentIssue(TypedDict):
    """Parent issue reference."""

    key: str
    summary: str


class IssueLink(TypedDict):
    """Issue link information."""

    type: str
    direction: str  # "outward" | "inward"
    key: str
    summary: str


class Subtask(TypedDict):
    """Subtask information."""

    key: str
    summary: str
    status: str


class Attachment(TypedDict):
    """Jira attachment metadata."""

    id: str
    filename: str
    size: int
    mimeType: str
    author: str
    created: str


class Ticket(TypedDict, total=False):
    """Full ticket data from Jira export."""

    # Core fields (always present in basic export)
    key: str
    summary: str
    issuetype: str
    status: str
    priority: str
    assignee: str
    reporter: str
    created: str
    updated: str
    description: str
    components: list[str]
    labels: list[str]
    parent: ParentIssue | None
    issuelinks: list[IssueLink]

    # Extended fields (full export only)
    project: str | None
    resolution: str | None
    resolutiondate: str | None
    statusCategory: str | None
    fixVersions: list[str]
    versions: list[str]
    votes: int
    watches: int
    subtasks: list[Subtask]
    assigneeDisplayName: str | None
    reporterDisplayName: str | None
    creator: str
    creatorDisplayName: str | None
    duedate: str | None

    # Attachments (if --with-attachments)
    attachments: list[Attachment]

    # Custom fields (if --all-fields)
    custom_fields: dict[str, object]

    # Pull requests (if --with-prs)
    pullRequests: list[dict[str, str]]


class ReportTicket(TypedDict, total=False):
    """Ticket data for reports (lighter than full Ticket)."""

    key: str
    summary: str
    issuetype: str
    status: str
    statusCategory: str | None
    priority: str
    assignee: str
    assigneeDisplayName: str | None
    reporter: str | None
    reporterDisplayName: str | None
    labels: list[str]
    components: list[str]
    project: str | None
    resolution: str | None
    fixVersions: list[str]
    duedate: str | None
    created: str
    updated: str
    parent: ParentIssue | None


class MyTicket(TypedDict):
    """Minimal ticket data for 'my' command."""

    key: str
    status: str
    created: str
    summary: str


class SearchResult(TypedDict):
    """Single search result row."""

    key: str
    summary: str
    status: str
    type: str
    priority: str
    assignee: str
    created: str


class FrontMatter(TypedDict, total=False):
    """YAML front matter from reports."""

    title: str
    generated: str
    query: str
    jql: str
    board: str
    sprint: str
    label: str
    group_by: str
    refresh: str
    report: str


class Credentials(TypedDict, total=False):
    """User credentials from config file."""

    email: str
    api_token: str
    site: str


class ReportDef(TypedDict, total=False):
    """Report definition from zproject.toml."""

    query: str
    jql: str
    board: int
    sprint: int
    group_by: str
    label: str
    title: str
    full: bool


class IssueTypeDef(TypedDict):
    """Issue type metadata."""

    subtask: bool


class LinkTypeDef(TypedDict):
    """Link type metadata."""

    outward: str
    inward: str


class FieldDef(TypedDict, total=False):
    """Field metadata.

    Type uses bracket notation for arrays: "[option]", "[string]".
    Scalar types: "option", "string", "number", "resolution", etc.
    """

    name: str
    type: str


class ZSchema(TypedDict, total=False):
    """Cached Jira instance metadata.

    Stored per-profile at ~/.cache/zaira/schema_PROFILE.json.
    Generated by 'zaira info --save' or 'zaira init'.
    """

    # Schema format version
    version: int

    # Field ID to metadata (e.g., "customfield_12345": {"name": "Epic Link", "type": "[option]"})
    fields: dict[str, FieldDef]

    # Status name to category mapping (e.g., "In Progress": "In Progress")
    statuses: dict[str, str | None]

    # Priority names in order
    priorities: list[str]

    # Issue type name to metadata
    issueTypes: dict[str, IssueTypeDef]

    # Link type name to metadata
    linkTypes: dict[str, LinkTypeDef]


class EditmetaFieldDef(TypedDict, total=False):
    """Editable field metadata from editmeta API.

    Keyed by field name in the YAML file. The Jira field ID is stored as 'id'.
    """

    id: str  # Jira field ID (e.g., "customfield_12345" or "summary")
    type: str
    required: bool
    allowedValues: list[str]


class EditmetaSchema(TypedDict, total=False):
    """Cached editmeta for a project.

    Stored as YAML at ~/.cache/zaira/editmeta_PROFILE_PROJECT.yaml.
    Generated by 'zaira learn ISSUE-KEY'. Human-editable.
    """

    project: str
    issueType: str
    learnedFrom: list[str]
    fields: dict[str, EditmetaFieldDef]


class ProjectSchema(TypedDict, total=False):
    """Cached project-specific metadata.

    Stored at ~/.cache/zaira/zproject_PROFILE_PROJECT.json.
    """

    components: list[str]
    labels: list[str]


@dataclass
class BundleChanges:
    """Files changed during a bundle install or update."""

    added: list[str]
    modified: list[str]
    removed: list[str]


@dataclass
class FieldError:
    """Validation error from check_field_allowed."""

    field: str
    suggestions: list[str]


@dataclass
class PageInfo:
    """Basic page metadata returned by _get_page_info."""

    parent_id: str | None
    space_key: str | None


# === Utility functions ===


def get_user_identifier(user: Any) -> str | None:
    """Safely extract user identifier, handling GDPR-restricted fields.

    Args:
        user: Jira user object (from jira library)

    Returns:
        User identifier string or None if user is None/empty
    """
    if not user:
        return None
    # Try emailAddress first, then displayName, then name
    for attr in ("emailAddress", "displayName", "name", "accountId"):
        try:
            val = getattr(user, attr, None)
            if val:
                return val
        except Exception:
            continue
    return "Unknown"


def yaml_quote(val: str) -> str:
    """Quote a string for safe YAML output.

    Args:
        val: String value to quote

    Returns:
        Quoted string if special characters present, otherwise unchanged
    """
    if any(c in val for c in ":{}[]&*#?|-<>=!%@\\\"'\n"):
        escaped = val.replace('"', '\\"')
        return f'"{escaped}"'
    return val
