from __future__ import annotations

from typing import Any, ClassVar

from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import MinLengthValidator
from django.db import models
from ninja import Schema


class OptimizationFeatures(models.Model):
    objects: ClassVar[models.Manager[OptimizationFeatures]]
    DoesNotExist: ClassVar[type[ObjectDoesNotExist]]
    trace_id = models.CharField(max_length=36, primary_key=True, validators=[MinLengthValidator(36)])
    original_code = models.TextField(null=True, blank=True)
    dependency_code = models.TextField(null=True, blank=True)
    line_profiler_results = models.TextField(null=True, blank=True)
    user_id = models.TextField(null=True, blank=True)
    optimizations_raw = models.JSONField(null=True, blank=True)
    optimizations_post = models.JSONField(null=True, blank=True)
    explanations_raw = models.JSONField(null=True, blank=True)
    explanations_post = models.JSONField(null=True, blank=True)
    speedup_ratio = models.JSONField(null=True, blank=True)
    original_runtime = models.FloatField(null=True, blank=True)
    optimized_runtime = models.JSONField(null=True, blank=True)
    optimized_line_profiler_results = models.JSONField(null=True, blank=True)
    is_correct = models.JSONField(null=True, blank=True)
    generated_test = ArrayField(models.TextField(), null=True, blank=True)
    instrumented_generated_test = ArrayField(models.TextField(), null=True, blank=True)
    instrumented_perf_test = ArrayField(models.TextField(), null=True, blank=True)
    test_framework = models.CharField(max_length=32, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    aiservice_commit_id = models.CharField(max_length=50, null=True, blank=True)
    metadata = models.JSONField(null=True, blank=True)
    experiment_metadata = models.JSONField(null=True, blank=True)
    final_explanation = models.TextField(null=True, blank=True)
    ranking = models.JSONField(null=True, blank=True)
    optimizations_origin = models.JSONField(null=True, blank=True)

    # PR suggestions or create Approval fields
    approval_required = models.BooleanField(default=False)
    approval_status = models.CharField(max_length=20, null=True, blank=True)
    approval_user = models.CharField(max_length=255, null=True, blank=True)
    approval_timestamp = models.DateTimeField(null=True, blank=True)
    slack_message_ts = models.CharField(max_length=50, null=True, blank=True)
    organization = models.CharField(max_length=255, null=True, blank=True)
    repository = models.CharField(max_length=255, null=True, blank=True)
    review_quality = models.CharField(max_length=255, null=True, blank=True)
    review_explanation = models.CharField(max_length=255, null=True, blank=True)
    calling_fn_details = models.CharField(max_length=1100, null=True, blank=True)

    class Meta:
        managed = False
        db_table = "optimization_features"


class OptimizationEvents(models.Model):
    objects: ClassVar[models.Manager[OptimizationEvents]]
    id = models.CharField(max_length=36, primary_key=True, editable=False)
    event_type = models.CharField(max_length=64)  # 'pr_created', 'pr_merged', 'pr_closed'
    user_id = models.CharField(max_length=255, null=True, blank=True)
    repository_id = models.CharField(max_length=255, null=True, blank=True)
    trace_id = models.CharField(max_length=36, null=True, blank=True, unique=True)
    pr_id = models.CharField(max_length=255, null=True, blank=True, unique=True)
    api_key_id = models.IntegerField(null=True, blank=True)
    llm_cost = models.FloatField(null=True, blank=True)
    metadata = models.JSONField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    current_username = models.CharField(max_length=255, null=True, blank=True)
    baseBranch = models.CharField(max_length=255, null=True, blank=True)
    pr_url = models.CharField(max_length=255, null=True, blank=True)
    is_optimization_found = models.BooleanField(null=True, blank=True)
    is_staging = models.BooleanField(null=True, blank=True)
    status = models.CharField(max_length=255, null=True, blank=True)
    function_name = models.CharField(max_length=255, null=True, blank=True)
    file_path = models.CharField(max_length=255, null=True, blank=True)
    speedup_x = models.FloatField(null=True, blank=True)
    speedup_pct = models.FloatField(null=True, blank=True)

    class Meta:
        managed = False
        db_table = "optimization_events"


class Repositories(models.Model):
    objects: ClassVar[models.Manager[Repositories]]
    DoesNotExist: ClassVar[type[ObjectDoesNotExist]]
    id = models.CharField(max_length=255, primary_key=True)
    github_repo_id = models.CharField(max_length=255, unique=True)
    installation_id = models.IntegerField()
    name = models.CharField(max_length=255)
    full_name = models.CharField(max_length=255)
    is_private = models.BooleanField()
    is_active = models.BooleanField(default=True)
    has_github_action = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    last_optimized = models.DateTimeField(null=True, blank=True)
    optimizations_limit = models.IntegerField(null=True, blank=True)
    optimizations_used = models.IntegerField(default=0)

    class Meta:
        managed = False
        db_table = "repositories"


class LoggingSchema(Schema):
    trace_id: str
    speedup_ratio: dict[str, float | int | None] | None
    original_runtime: float | int | None
    optimized_runtime: dict[str, float | int | None] | None
    is_correct: dict[str, bool] | None
    optimized_line_profiler_results: dict[str, str] | None = None
    metadata: dict[str, Any] | None = None
    optimizations_post: dict[str, str] | None = None


class LoggingErrorResponseSchema(Schema):
    error: str
