import uuid

from app.core.celery_app import celery_app
from app.db.session import SessionLocal
from app.models.knowledge import ExtractedText, KnowledgeSource, SourceStatus
from app.services.cleaning import clean_text
from app.services.extraction import extract_text
from app.ws.events import publish_job_event


@celery_app.task(name="documents.extract_and_clean")
def extract_and_clean(knowledge_source_id: str) -> None:
    db = SessionLocal()
    source_id = uuid.UUID(knowledge_source_id)
    try:
        source = db.get(KnowledgeSource, source_id)
        if source is None:
            return

        source.status = SourceStatus.extracting
        db.commit()
        publish_job_event(knowledge_source_id, {"status": "extracting"})

        raw_text = extract_text(source.storage_path, source.file_type)

        source.status = SourceStatus.extracted
        db.commit()
        publish_job_event(knowledge_source_id, {"status": "extracted"})

        source.status = SourceStatus.cleaning
        db.commit()
        publish_job_event(knowledge_source_id, {"status": "cleaning"})

        cleaned, report = clean_text(raw_text)

        extracted = db.query(ExtractedText).filter_by(knowledge_source_id=source_id).one_or_none()
        if extracted is None:
            extracted = ExtractedText(knowledge_source_id=source_id)
            db.add(extracted)
        extracted.raw_text = raw_text
        extracted.cleaned_text = cleaned
        extracted.cleaning_report = report
        extracted.is_confirmed = False

        source.status = SourceStatus.cleaned
        db.commit()
        publish_job_event(knowledge_source_id, {"status": "cleaned", "report": report})

    except Exception as exc:  # noqa: BLE001
        db.rollback()
        source = db.get(KnowledgeSource, source_id)
        if source:
            source.status = SourceStatus.failed
            source.error_message = str(exc)
            db.commit()
        publish_job_event(knowledge_source_id, {"status": "failed", "error": str(exc)})
        raise
    finally:
        db.close()
