"""GitHub integration models.

This module contains Django models for the GitHub integration:
- GitHubInstallation: Represents a GitHub App installation linked to a workspace
- GitHubRepository: Represents a GitHub repository being monitored
"""

import logging

from django.db import models

from accounts.models import Workspace
from core.utils.encryption import decrypt_value, encrypt_value
from integrations.models.base import TimestampedModel
from sources.models import Source

logger = logging.getLogger(__name__)


class GitHubInstallation(TimestampedModel):
    """Represents a GitHub App installation linked to a Dexxy workspace.

    A workspace can have at most one GitHub App installation.
    The installation grants access to selected repositories.
    """

    ACCOUNT_TYPE_CHOICES = [
        ("User", "User"),
        ("Organization", "Organization"),
    ]

    workspace = models.OneToOneField(
        Workspace,
        on_delete=models.CASCADE,
        related_name="github_installation",
    )
    installation_id = models.BigIntegerField(unique=True, help_text="GitHub's installation ID")
    account_login = models.CharField(max_length=255, help_text="GitHub username or org name")
    account_type = models.CharField(max_length=20, choices=ACCOUNT_TYPE_CHOICES)
    account_id = models.BigIntegerField(help_text="GitHub's account ID")
    account_avatar_url = models.URLField(max_length=500, blank=True, default="")

    # Token storage (encrypted)
    _access_token = models.TextField(blank=True, db_column="access_token")
    token_expires_at = models.DateTimeField(null=True, blank=True)

    # Permissions and state
    permissions = models.JSONField(default=dict, blank=True)
    suspended_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        app_label = "integrations"
        verbose_name = "GitHub Installation"
        verbose_name_plural = "GitHub Installations"

    def __str__(self) -> str:
        return f"{self.account_login} ({self.account_type})"

    @property
    def is_suspended(self) -> bool:
        """Check if the installation is currently suspended."""
        return self.suspended_at is not None

    @property
    def access_token(self) -> str:
        """Get the decrypted access token."""
        if not self._access_token:
            return ""
        try:
            return decrypt_value(self._access_token)
        except ValueError:
            logger.warning(
                "Failed to decrypt access token for installation %s",
                self.installation_id,
            )
            return ""

    @access_token.setter
    def access_token(self, value: str) -> None:
        """Set the access token with Fernet encryption."""
        if value:
            self._access_token = encrypt_value(value)
        else:
            self._access_token = ""


class GitHubRepository(TimestampedModel):
    """Represents a GitHub repository being monitored within an installation.

    Each repository is linked to a Source record for unified data model.
    """

    SYNC_STATUS_CHOICES = [
        ("pending", "Pending"),
        ("syncing", "Syncing"),
        ("active", "Active"),
        ("error", "Error"),
        ("paused", "Paused"),
        ("disabled", "Disabled"),
    ]

    installation = models.ForeignKey(
        GitHubInstallation,
        on_delete=models.CASCADE,
        related_name="repositories",
    )
    source = models.OneToOneField(
        Source,
        on_delete=models.CASCADE,
        related_name="github_repository",
    )
    repo_id = models.BigIntegerField(help_text="GitHub's repository ID")
    owner = models.CharField(max_length=255, help_text="Repository owner (user/org)")
    name = models.CharField(max_length=255, help_text="Repository name")
    full_name = models.CharField(max_length=512, help_text="Full name (owner/name)")
    private = models.BooleanField(default=False)

    # Sync state
    sync_status = models.CharField(max_length=20, choices=SYNC_STATUS_CHOICES, default="pending")
    last_sync_at = models.DateTimeField(null=True, blank=True)
    last_sync_error = models.TextField(blank=True)
    sync_cursors = models.JSONField(
        default=dict,
        blank=True,
        help_text="Pagination cursors for incremental sync",
    )

    # Soft delete for data retention
    is_archived = models.BooleanField(default=False)

    class Meta:
        app_label = "integrations"
        verbose_name = "GitHub Repository"
        verbose_name_plural = "GitHub Repositories"
        unique_together = [("installation", "repo_id")]
        indexes = [
            models.Index(fields=["sync_status"]),
            models.Index(fields=["is_archived"]),
        ]

    def __str__(self) -> str:
        return self.full_name

    @property
    def html_url(self) -> str:
        """Get the GitHub URL for this repository."""
        return f"https://github.com/{self.full_name}"
