# [DEF:backend.src.api.routes.git_schemas:Module]
#
# @TIER:      STANDARD
# @SEMANTICS: git, schemas, pydantic, api, contracts
# @PURPOSE:   Defines Pydantic models for the Git integration API layer.
# @LAYER:     API
# @RELATION:  DEPENDS_ON -> backend.src.models.git
#
# @INVARIANT: All schemas must be compatible with the FastAPI router.

from pydantic import BaseModel, Field
from typing import Any, Dict, List, Optional
from datetime import datetime
from src.models.git import GitProvider, GitStatus, SyncStatus

# [DEF:GitServerConfigBase:Class]
# @TIER: TRIVIAL
# @PURPOSE: Base schema for Git server configuration attributes.
class GitServerConfigBase(BaseModel):
    name: str = Field(..., description="Display name for the Git server")
    provider: GitProvider = Field(..., description="Git provider (GITHUB, GITLAB, GITEA)")
    url: str = Field(..., description="Server base URL")
    pat: str = Field(..., description="Personal Access Token")
    pat: str = Field(..., description="Personal Access Token")
    default_repository: Optional[str] = Field(None, description="Default repository path (org/repo)")
    default_branch: Optional[str] = Field("main", description="Default branch logic/name")
# [/DEF:GitServerConfigBase:Class]

# [DEF:GitServerConfigUpdate:Class]
# @PURPOSE: Schema for updating an existing Git server configuration.
class GitServerConfigUpdate(BaseModel):
    name: Optional[str] = Field(None, description="Display name for the Git server")
    provider: Optional[GitProvider] = Field(None, description="Git provider (GITHUB, GITLAB, GITEA)")
    url: Optional[str] = Field(None, description="Server base URL")
    pat: Optional[str] = Field(None, description="Personal Access Token")
    default_repository: Optional[str] = Field(None, description="Default repository path (org/repo)")
    default_branch: Optional[str] = Field(None, description="Default branch logic/name")
# [/DEF:GitServerConfigUpdate:Class]

# [DEF:GitServerConfigCreate:Class]
# @PURPOSE: Schema for creating a new Git server configuration.
class GitServerConfigCreate(GitServerConfigBase):
    """Schema for creating a new Git server configuration."""
    config_id: Optional[str] = Field(None, description="Optional config ID, useful for testing an existing config without sending its full PAT")
# [/DEF:GitServerConfigCreate:Class]

# [DEF:GitServerConfigSchema:Class]
# @PURPOSE: Schema for representing a Git server configuration with metadata.
class GitServerConfigSchema(GitServerConfigBase):
    """Schema for representing a Git server configuration with metadata."""
    id: str
    status: GitStatus
    last_validated: datetime

    class Config:
        from_attributes = True
# [/DEF:GitServerConfigSchema:Class]

# [DEF:GitRepositorySchema:Class]
# @PURPOSE: Schema for tracking a local Git repository linked to a dashboard.
class GitRepositorySchema(BaseModel):
    """Schema for tracking a local Git repository linked to a dashboard."""
    id: str
    dashboard_id: int
    config_id: str
    remote_url: str
    local_path: str
    current_branch: str
    sync_status: SyncStatus

    class Config:
        from_attributes = True
# [/DEF:GitRepositorySchema:Class]

# [DEF:BranchSchema:Class]
# @PURPOSE: Schema for representing a Git branch metadata.
class BranchSchema(BaseModel):
    """Schema for representing a Git branch."""
    name: str
    commit_hash: str
    is_remote: bool
    last_updated: datetime
# [/DEF:BranchSchema:Class]

# [DEF:CommitSchema:Class]
# @PURPOSE: Schema for representing Git commit details.
class CommitSchema(BaseModel):
    """Schema for representing a Git commit."""
    hash: str
    author: str
    email: str
    timestamp: datetime
    message: str
    files_changed: List[str]
# [/DEF:CommitSchema:Class]

# [DEF:BranchCreate:Class]
# @PURPOSE: Schema for branch creation requests.
class BranchCreate(BaseModel):
    """Schema for branch creation requests."""
    name: str
    from_branch: str
# [/DEF:BranchCreate:Class]

# [DEF:BranchCheckout:Class]
# @PURPOSE: Schema for branch checkout requests.
class BranchCheckout(BaseModel):
    """Schema for branch checkout requests."""
    name: str
# [/DEF:BranchCheckout:Class]

# [DEF:CommitCreate:Class]
# @PURPOSE: Schema for staging and committing changes.
class CommitCreate(BaseModel):
    """Schema for staging and committing changes."""
    message: str
    files: List[str]
# [/DEF:CommitCreate:Class]

# [DEF:ConflictResolution:Class]
# @PURPOSE: Schema for resolving merge conflicts.
class ConflictResolution(BaseModel):
    """Schema for resolving merge conflicts."""
    file_path: str
    resolution: str = Field(pattern="^(mine|theirs|manual)$")
    content: Optional[str] = None
# [/DEF:ConflictResolution:Class]


# [DEF:MergeStatusSchema:Class]
# @PURPOSE: Schema representing unfinished merge status for repository.
class MergeStatusSchema(BaseModel):
    has_unfinished_merge: bool
    repository_path: str
    git_dir: str
    current_branch: str
    merge_head: Optional[str] = None
    merge_message_preview: Optional[str] = None
    conflicts_count: int = 0
# [/DEF:MergeStatusSchema:Class]


# [DEF:MergeConflictFileSchema:Class]
# @PURPOSE: Schema describing one conflicted file with optional side snapshots.
class MergeConflictFileSchema(BaseModel):
    file_path: str
    mine: Optional[str] = None
    theirs: Optional[str] = None
# [/DEF:MergeConflictFileSchema:Class]


# [DEF:MergeResolveRequest:Class]
# @PURPOSE: Request schema for resolving one or multiple merge conflicts.
class MergeResolveRequest(BaseModel):
    resolutions: List[ConflictResolution] = Field(default_factory=list)
# [/DEF:MergeResolveRequest:Class]


# [DEF:MergeContinueRequest:Class]
# @PURPOSE: Request schema for finishing merge with optional explicit commit message.
class MergeContinueRequest(BaseModel):
    message: Optional[str] = None
# [/DEF:MergeContinueRequest:Class]

# [DEF:DeploymentEnvironmentSchema:Class]
# @PURPOSE: Schema for representing a target deployment environment.
class DeploymentEnvironmentSchema(BaseModel):
    """Schema for representing a target deployment environment."""
    id: str
    name: str
    superset_url: str
    is_active: bool

    class Config:
        from_attributes = True
# [/DEF:DeploymentEnvironmentSchema:Class]

# [DEF:DeployRequest:Class]
# @PURPOSE: Schema for dashboard deployment requests.
class DeployRequest(BaseModel):
    """Schema for deployment requests."""
    environment_id: str
# [/DEF:DeployRequest:Class]

# [DEF:RepoInitRequest:Class]
# @PURPOSE: Schema for repository initialization requests.
class RepoInitRequest(BaseModel):
    """Schema for repository initialization requests."""
    config_id: str
    remote_url: str
# [/DEF:RepoInitRequest:Class]


# [DEF:RepositoryBindingSchema:Class]
# @PURPOSE: Schema describing repository-to-config binding and provider metadata.
class RepositoryBindingSchema(BaseModel):
    dashboard_id: int
    config_id: str
    provider: GitProvider
    remote_url: str
    local_path: str
# [/DEF:RepositoryBindingSchema:Class]

# [DEF:RepoStatusBatchRequest:Class]
# @PURPOSE: Schema for requesting repository statuses for multiple dashboards in a single call.
class RepoStatusBatchRequest(BaseModel):
    dashboard_ids: List[int] = Field(default_factory=list, description="Dashboard IDs to resolve repository statuses for")
# [/DEF:RepoStatusBatchRequest:Class]


# [DEF:RepoStatusBatchResponse:Class]
# @PURPOSE: Schema for returning repository statuses keyed by dashboard ID.
class RepoStatusBatchResponse(BaseModel):
    statuses: Dict[str, Dict[str, Any]]
# [/DEF:RepoStatusBatchResponse:Class]


# [DEF:GiteaRepoSchema:Class]
# @PURPOSE: Schema describing a Gitea repository.
class GiteaRepoSchema(BaseModel):
    name: str
    full_name: str
    private: bool = False
    clone_url: Optional[str] = None
    html_url: Optional[str] = None
    ssh_url: Optional[str] = None
    default_branch: Optional[str] = None
# [/DEF:GiteaRepoSchema:Class]


# [DEF:GiteaRepoCreateRequest:Class]
# @PURPOSE: Request schema for creating a Gitea repository.
class GiteaRepoCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=255)
    private: bool = True
    description: Optional[str] = None
    auto_init: bool = True
    default_branch: Optional[str] = "main"
# [/DEF:GiteaRepoCreateRequest:Class]


# [DEF:RemoteRepoSchema:Class]
# @PURPOSE: Provider-agnostic remote repository payload.
class RemoteRepoSchema(BaseModel):
    provider: GitProvider
    name: str
    full_name: str
    private: bool = False
    clone_url: Optional[str] = None
    html_url: Optional[str] = None
    ssh_url: Optional[str] = None
    default_branch: Optional[str] = None
# [/DEF:RemoteRepoSchema:Class]


# [DEF:RemoteRepoCreateRequest:Class]
# @PURPOSE: Provider-agnostic repository creation request.
class RemoteRepoCreateRequest(BaseModel):
    name: str = Field(..., min_length=1, max_length=255)
    private: bool = True
    description: Optional[str] = None
    auto_init: bool = True
    default_branch: Optional[str] = "main"
# [/DEF:RemoteRepoCreateRequest:Class]


# [DEF:PromoteRequest:Class]
# @PURPOSE: Request schema for branch promotion workflow.
class PromoteRequest(BaseModel):
    from_branch: str = Field(..., min_length=1, max_length=255)
    to_branch: str = Field(..., min_length=1, max_length=255)
    mode: str = Field(default="mr", pattern="^(mr|direct)$")
    title: Optional[str] = None
    description: Optional[str] = None
    reason: Optional[str] = None
    draft: bool = False
    remove_source_branch: bool = False
# [/DEF:PromoteRequest:Class]


# [DEF:PromoteResponse:Class]
# @PURPOSE: Response schema for promotion operation result.
class PromoteResponse(BaseModel):
    mode: str
    from_branch: str
    to_branch: str
    status: str
    url: Optional[str] = None
    reference_id: Optional[str] = None
    policy_violation: bool = False
# [/DEF:PromoteResponse:Class]

# [/DEF:backend.src.api.routes.git_schemas:Module]
