"""
SQLite veritabanı yönetimi modülü
"""
import sqlite3
import os
import re
import threading
import logging
from datetime import datetime, timezone
from typing import Optional, List, Dict

# Logger oluştur
logger = logging.getLogger(__name__)


class Database:
    """SQLite veritabanı yönetim sınıfı (thread-safe)"""
    
    def __init__(self, db_path: str = "data/videos.db"):
        self.db_path = db_path
        # Thread-local storage: Her thread'in kendi connection'ı olacak
        self._local = threading.local()
        
    def connect(self):
        """Veritabanı bağlantısı oluştur (thread-safe)"""
        # Her thread'in kendi connection'ı var mı kontrol et
        if not hasattr(self._local, 'conn') or self._local.conn is None:
            # Dizin yoksa oluştur
            os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
            # check_same_thread=False: Thread-safe çalışma için
            self._local.conn = sqlite3.connect(
                self.db_path,
                check_same_thread=False
            )
            self._local.conn.row_factory = sqlite3.Row
        return self._local.conn
    
    def init_database(self):
        """Veritabanı şemasını oluştur"""
        conn = self.connect()
        cursor = conn.cursor()
        
        # Channels tablosu
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS channels (
                channel_id TEXT PRIMARY KEY,
                channel_name TEXT,
                channel_url TEXT,
                last_checked_utc TEXT,
                created_at_utc TEXT DEFAULT (datetime('now'))
            )
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_channels_last_checked 
            ON channels(last_checked_utc)
        """)
        
        # Videos tablosu
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS videos (
                video_id TEXT PRIMARY KEY,
                channel_id TEXT,
                video_title TEXT,
                video_url TEXT,
                published_at_utc TEXT,
                processed_at_utc TEXT,
                transcript_status INTEGER DEFAULT 0,
                transcript_language TEXT,
                transcript_raw TEXT,
                transcript_clean TEXT,
                last_updated_utc TEXT DEFAULT (datetime('now'))
            )
        """)
        
        # Index'ler
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_videos_channel_id 
            ON videos(channel_id)
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_videos_published_at_utc 
            ON videos(published_at_utc)
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_videos_transcript_status 
            ON videos(transcript_status)
        """)
        
        cursor.execute("""
            CREATE INDEX IF NOT EXISTS idx_videos_processed_at_utc 
            ON videos(processed_at_utc)
        """)
        
        conn.commit()
        logger.info("[DATABASE] ✅ Veritabanı başarıyla initialize edildi")
    
    def close(self):
        """Veritabanı bağlantısını kapat (thread-safe)"""
        if hasattr(self._local, 'conn') and self._local.conn:
            self._local.conn.close()
            self._local.conn = None
    
    def _validate_video_id(self, video_id: str) -> bool:
        """Video ID formatını doğrula (SQL injection koruması)"""
        if not video_id or len(video_id) > 20:
            return False
        # YouTube video ID: 11 karakter, alfanumerik + _ -
        return bool(re.match(r'^[a-zA-Z0-9_-]{11}$', video_id))
    
    def _validate_channel_id(self, channel_id: str) -> bool:
        """Channel ID formatını doğrula (SQL injection koruması)"""
        if not channel_id or len(channel_id) > 50:
            return False
        # YouTube channel ID: UC ile başlayan 24 karakter
        return bool(re.match(r'^UC[a-zA-Z0-9_-]{22}$', channel_id))
    
    def is_video_processed(self, video_id: str) -> bool:
        """Video işlenmiş mi kontrol et"""
        if not self._validate_video_id(video_id):
            raise ValueError(f"Geçersiz video_id formatı: {video_id}")
        conn = self.connect()
        cursor = conn.cursor()
        cursor.execute("SELECT video_id FROM videos WHERE video_id = ?", (video_id,))
        return cursor.fetchone() is not None
    
    def get_pending_videos(self) -> List[Dict]:
        """İşlenmeyi bekleyen videoları getir (status=0)"""
        conn = self.connect()
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM videos 
            WHERE transcript_status = 0 
            ORDER BY published_at_utc DESC
        """)
        return [dict(row) for row in cursor.fetchall()]
    
    def add_video(self, video_data: Dict):
        """Yeni video ekle (status=0 olarak)"""
        # Input validation
        video_id = video_data.get('video_id')
        channel_id = video_data.get('channel_id')
        
        if not self._validate_video_id(video_id):
            raise ValueError(f"Geçersiz video_id formatı: {video_id}")
        
        if channel_id and not self._validate_channel_id(channel_id):
            raise ValueError(f"Geçersiz channel_id formatı: {channel_id}")
        
        conn = self.connect()
        cursor = conn.cursor()
        cursor.execute("""
            INSERT OR IGNORE INTO videos 
            (video_id, channel_id, video_title, video_url, published_at_utc, transcript_status)
            VALUES (?, ?, ?, ?, ?, 0)
        """, (
            video_id,
            channel_id,
            video_data.get('video_title', '')[:500],  # Max length
            video_data.get('video_url', '')[:500],  # Max length
            video_data.get('published_at_utc')
        ))
        conn.commit()
    
    def update_video_transcript(self, video_id: str, raw: str, clean: str, 
                               status: int, language: Optional[str] = None):
        """Video transcript'ini güncelle"""
        # Input validation
        if not self._validate_video_id(video_id):
            raise ValueError(f"Geçersiz video_id formatı: {video_id}")
        
        if status not in [0, 1, 2]:
            raise ValueError(f"Geçersiz status değeri: {status}")
        
        conn = self.connect()
        cursor = conn.cursor()
        now_utc = datetime.now(timezone.utc).isoformat()
        cursor.execute("""
            UPDATE videos 
            SET transcript_raw = ?, 
                transcript_clean = ?, 
                transcript_status = ?,
                transcript_language = ?,
                processed_at_utc = ?,
                last_updated_utc = ?
            WHERE video_id = ?
        """, (raw, clean, status, language, now_utc, now_utc, video_id))
        conn.commit()
    
    def get_processed_videos(self, limit: Optional[int] = None, 
                            channel_id: Optional[str] = None) -> List[Dict]:
        """İşlenmiş videoları getir (status=1)"""
        # Input validation
        if channel_id and not self._validate_channel_id(channel_id):
            raise ValueError(f"Geçersiz channel_id formatı: {channel_id}")
        
        if limit is not None and (not isinstance(limit, int) or limit < 1 or limit > 1000):
            raise ValueError(f"Geçersiz limit değeri: {limit} (1-1000 arası olmalı)")
        
        conn = self.connect()
        cursor = conn.cursor()
        query = """
            SELECT * FROM videos 
            WHERE transcript_status = 1
        """
        params = []
        
        if channel_id:
            query += " AND channel_id = ?"
            params.append(channel_id)
        
        query += " ORDER BY published_at_utc DESC"
        
        if limit:
            query += " LIMIT ?"
            params.append(limit)
        
        cursor.execute(query, params)
        return [dict(row) for row in cursor.fetchall()]
    
    def mark_video_failed(self, video_id: str, reason: Optional[str] = None):
        """Video'yu başarısız olarak işaretle (status=2)"""
        # Input validation
        if not self._validate_video_id(video_id):
            raise ValueError(f"Geçersiz video_id formatı: {video_id}")
        
        conn = self.connect()
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE videos 
            SET transcript_status = 2,
                last_updated_utc = ?
            WHERE video_id = ?
        """, (datetime.now(timezone.utc).isoformat(), video_id))
        conn.commit()
    
    def is_transcript_cached(self, video_id: str, cache_days: int = 3) -> bool:
        """
        Video transcript'i cache'de mi ve hala geçerli mi kontrol et
        
        Args:
            video_id: Video ID
            cache_days: Cache geçerlilik süresi (gün)
        
        Returns:
            True eğer cache'de ve geçerliyse, False değilse
        """
        if not self._validate_video_id(video_id):
            return False
        
        conn = self.connect()
        cursor = conn.cursor()
        # 3 gün içinde işlenmiş ve başarılı (status=1) transcript var mı?
        cursor.execute("""
            SELECT processed_at_utc, transcript_status, transcript_clean
            FROM videos 
            WHERE video_id = ? 
            AND transcript_status = 1
            AND processed_at_utc IS NOT NULL
        """, (video_id,))
        
        row = cursor.fetchone()
        if not row:
            return False
        
        # processed_at_utc'yi parse et ve 3 gün kontrolü yap
        try:
            processed_at = datetime.fromisoformat(row['processed_at_utc'].replace('Z', '+00:00'))
            now = datetime.now(timezone.utc)
            days_diff = (now - processed_at).days
            
            # 3 gün içindeyse ve transcript_clean varsa cache geçerli
            if days_diff < cache_days and row['transcript_clean']:
                return True
        except (ValueError, AttributeError):
            return False
        
        return False
    
    def get_cached_transcript(self, video_id: str) -> Optional[Dict]:
        """
        Cache'den transcript'i getir (eğer varsa)
        
        Args:
            video_id: Video ID
        
        Returns:
            Video dict (transcript_clean ile) veya None
        """
        if not self._validate_video_id(video_id):
            return None
        
        conn = self.connect()
        cursor = conn.cursor()
        cursor.execute("""
            SELECT * FROM videos 
            WHERE video_id = ? 
            AND transcript_status = 1
            AND transcript_clean IS NOT NULL
        """, (video_id,))
        
        row = cursor.fetchone()
        if row:
            return dict(row)
        
        return None

