"""
DSFA Corpus Store — Database operations and data classes.

Contains:
- DSFAChunkPayload: Qdrant point payload schema
- DSFASearchResult: Search result with attribution
- DSFACorpusStore: PostgreSQL operations for DSFA corpus
"""

import hashlib
import uuid
from typing import List, Dict, Optional
from dataclasses import dataclass

import asyncpg

from dsfa_sources_registry import LICENSE_REGISTRY


@dataclass
class DSFAChunkPayload:
    """Payload schema for Qdrant points."""
    chunk_id: str
    document_id: str
    source_id: str
    content: str
    section_title: Optional[str] = None
    source_code: str = ""
    source_name: str = ""
    attribution_text: str = ""
    license_code: str = ""
    attribution_required: bool = True
    document_type: str = ""
    category: str = ""
    language: str = "de"
    page_number: Optional[int] = None


@dataclass
class DSFASearchResult:
    """Search result with attribution."""
    chunk_id: str
    content: str
    score: float
    source_code: str
    source_name: str
    attribution_text: str
    license_code: str
    license_url: Optional[str]
    attribution_required: bool
    source_url: Optional[str]
    document_type: str
    category: str
    section_title: Optional[str]
    page_number: Optional[int]


class DSFACorpusStore:
    """Database operations for DSFA corpus."""

    def __init__(self, pool: asyncpg.Pool):
        self.pool = pool

    async def register_source(self, source_data: Dict) -> str:
        """Register a DSFA source in the database."""
        async with self.pool.acquire() as conn:
            existing = await conn.fetchval(
                "SELECT id FROM dsfa_sources WHERE source_code = $1",
                source_data["source_code"]
            )
            if existing:
                await conn.execute("""
                    UPDATE dsfa_sources SET
                        name = $2,
                        full_name = $3,
                        organization = $4,
                        source_url = $5,
                        eur_lex_celex = $6,
                        license_code = $7,
                        license_url = $8,
                        attribution_required = $9,
                        attribution_text = $10,
                        document_type = $11,
                        language = $12,
                        updated_at = NOW()
                    WHERE source_code = $1
                """,
                    source_data["source_code"],
                    source_data["name"],
                    source_data.get("full_name"),
                    source_data.get("organization"),
                    source_data.get("source_url"),
                    source_data.get("eur_lex_celex"),
                    source_data["license_code"],
                    source_data.get("license_url"),
                    LICENSE_REGISTRY.get(source_data["license_code"], {}).get("attribution_required", True),
                    source_data["attribution_text"],
                    source_data.get("document_type"),
                    source_data.get("language", "de")
                )
                return str(existing)
            else:
                source_id = await conn.fetchval("""
                    INSERT INTO dsfa_sources (
                        source_code, name, full_name, organization, source_url,
                        eur_lex_celex, license_code, license_url, attribution_required,
                        attribution_text, document_type, language
                    ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
                    RETURNING id
                """,
                    source_data["source_code"],
                    source_data["name"],
                    source_data.get("full_name"),
                    source_data.get("organization"),
                    source_data.get("source_url"),
                    source_data.get("eur_lex_celex"),
                    source_data["license_code"],
                    source_data.get("license_url"),
                    LICENSE_REGISTRY.get(source_data["license_code"], {}).get("attribution_required", True),
                    source_data["attribution_text"],
                    source_data.get("document_type"),
                    source_data.get("language", "de")
                )
                return str(source_id)

    async def get_source_by_code(self, source_code: str) -> Optional[Dict]:
        """Get source by its code."""
        async with self.pool.acquire() as conn:
            row = await conn.fetchrow(
                "SELECT * FROM dsfa_sources WHERE source_code = $1",
                source_code
            )
            if row:
                return dict(row)
            return None

    async def list_sources(self) -> List[Dict]:
        """List all registered sources."""
        async with self.pool.acquire() as conn:
            rows = await conn.fetch(
                "SELECT * FROM dsfa_sources ORDER BY source_code"
            )
            return [dict(row) for row in rows]

    async def create_document(
        self,
        source_id: str,
        title: str,
        file_name: Optional[str] = None,
        file_type: Optional[str] = None,
        minio_path: Optional[str] = None,
        original_url: Optional[str] = None,
        metadata: Optional[Dict] = None
    ) -> str:
        """Create a document record."""
        import json
        metadata_json = json.dumps(metadata or {})
        async with self.pool.acquire() as conn:
            doc_id = await conn.fetchval("""
                INSERT INTO dsfa_documents (
                    source_id, title, file_name, file_type, minio_path,
                    original_url, metadata
                ) VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)
                RETURNING id
            """,
                uuid.UUID(source_id),
                title,
                file_name,
                file_type,
                minio_path,
                original_url,
                metadata_json
            )
            return str(doc_id)

    async def create_chunk(
        self,
        document_id: str,
        source_id: str,
        content: str,
        chunk_index: int,
        section_title: Optional[str] = None,
        page_number: Optional[int] = None,
        category: Optional[str] = None,
        qdrant_point_id: Optional[str] = None,
        metadata: Optional[Dict] = None
    ) -> str:
        """Create a chunk record."""
        import json
        content_hash = hashlib.sha256(content.encode()).hexdigest()

        async with self.pool.acquire() as conn:
            chunk_id = await conn.fetchval("""
                INSERT INTO dsfa_document_chunks (
                    document_id, source_id, content, content_hash, chunk_index,
                    section_title, page_number, category, qdrant_point_id, metadata
                ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10::jsonb)
                RETURNING id
            """,
                uuid.UUID(document_id),
                uuid.UUID(source_id),
                content,
                content_hash,
                chunk_index,
                section_title,
                page_number,
                category,
                qdrant_point_id,
                json.dumps(metadata or {})
            )
            return str(chunk_id)

    async def get_chunk_with_attribution(self, chunk_id: str) -> Optional[Dict]:
        """Get a chunk with full source attribution."""
        async with self.pool.acquire() as conn:
            row = await conn.fetchrow("""
                SELECT * FROM dsfa_chunk_with_attribution
                WHERE chunk_id = $1
            """, uuid.UUID(chunk_id))
            if row:
                return dict(row)
            return None

    async def get_source_stats(self) -> List[Dict]:
        """Get aggregated stats per source."""
        async with self.pool.acquire() as conn:
            rows = await conn.fetch("SELECT * FROM dsfa_source_stats")
            return [dict(row) for row in rows]

    async def update_document_indexed(self, document_id: str, chunks_count: int):
        """Update document with indexing information."""
        async with self.pool.acquire() as conn:
            await conn.execute("""
                UPDATE dsfa_documents
                SET chunks_generated = $2,
                    last_indexed_at = NOW(),
                    text_extracted = true
                WHERE id = $1
            """, uuid.UUID(document_id), chunks_count)
