import os
import uuid

from django.db import transaction
from django.utils.text import slugify

from claims.models import Category, Claim, CounterArgument, EvidenceFile, Source, Tag


class DraftPublishError(Exception):
    pass


def _resolve_category(draft):
    if draft.category_slug:
        category = Category.objects.filter(slug=draft.category_slug).first()
        if category:
            return category

    if draft.new_category_name:
        category, _ = Category.objects.get_or_create(
            slug=slugify(draft.new_category_name),
            defaults={
                'name': draft.new_category_name,
                'description': draft.new_category_description or draft.new_category_name,
                'icon': draft.new_category_icon or 'bi-book',
            },
        )
        return category

    raise DraftPublishError('Bitte eine Kategorie auswählen oder eine neue angeben.')


def _get_or_create_tags(tag_names):
    tags = []
    for name in tag_names or []:
        clean = str(name).strip()
        if not clean:
            continue
        tag, _ = Tag.objects.get_or_create(name=clean, defaults={'slug': slugify(clean)})
        tags.append(tag)
    return tags


@transaction.atomic
def publish_draft(draft):
    if draft.status == draft.DraftStatus.PUBLISHED and draft.published_claim_id:
        return draft.published_claim

    if not draft.title or not draft.short_answer:
        raise DraftPublishError('Titel und Kurzantwort sind erforderlich.')

    category = _resolve_category(draft)
    claim = Claim.objects.create(
        category=category,
        title=draft.title,
        status=draft.claim_status or Claim.Status.UNBELEGT,
        short_answer=draft.short_answer,
        detailed_explanation=draft.detailed_explanation,
        evidence_level=draft.evidence_level or Claim.EvidenceLevel.MITTEL,
    )
    claim.tags.set(_get_or_create_tags(draft.tags))

    for source in draft.sources or []:
        url = (source.get('url') or '').strip()
        if not url:
            continue
        Source.objects.create(
            claim=claim,
            title=source.get('title') or url,
            organization=source.get('organization') or 'Unbekannt',
            url=url,
            description=source.get('description', ''),
        )

    for counter in draft.counter_arguments or []:
        argument = (counter.get('argument') or '').strip()
        response = (counter.get('response') or '').strip()
        if argument and response:
            CounterArgument.objects.create(claim=claim, argument=argument, response=response)

    if draft.uploaded_file:
        _attach_uploaded_file(draft, claim)

    draft.published_claim = claim
    draft.status = draft.DraftStatus.PUBLISHED
    draft.save(update_fields=['published_claim', 'status', 'updated_at'])
    return claim


def _attach_uploaded_file(draft, claim):
    if not draft.uploaded_file:
        return

    original_name = os.path.basename(draft.uploaded_file.name)
    ext = original_name.rsplit('.', 1)[-1].lower() if '.' in original_name else ''
    if ext not in {'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf'}:
        return

    evidence = EvidenceFile(claim=claim, title='')
    short_name = f'{uuid.uuid4().hex[:12]}.{ext}'
    with draft.uploaded_file.open('rb') as source_file:
        evidence.file.save(short_name, source_file, save=True)
