import logging
from itertools import chain
from django.http import JsonResponse
from django.views.generic import ListView
from django.views.generic.base import TemplateView
from django.db.models import Q, Value, CharField, IntegerField, Case, When
from django.db import models
from django.utils.text import slugify
from .models import Link, Page, Post
from .search_backend import search_backend
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.core.cache import cache
import hashlib
import json
import requests
import os
from qdrant_client import QdrantClient

logger = logging.getLogger(__name__)

def get_ollama_embedding(text):
    ollama_url = os.getenv("OLLAMA_URL", "http://ollama-service.ollama.svc.cluster.local:11434")
    model = os.getenv("OLLAMA_MODEL", "llama3")
    try:
        r = requests.post(f"{ollama_url}/api/embeddings", json={"model": model, "prompt": text}, timeout=5)
        r.raise_for_status()
        return r.json()["embedding"]
    except Exception as e:
        logger.error(f"Ollama embedding error: {e}")
        return None

@require_http_methods(["GET"])
def search_vector_api(request):
    query = request.GET.get('q', '').strip()
    if not query:
        return JsonResponse({'results': [], 'total': 0})

    qdrant_host = os.getenv("QDRANT_HOST", "192.168.1.2")
    qdrant_port = int(os.getenv("QDRANT_PORT", "6333"))
    collection = os.getenv("COLLECTION_NAME", "links")

    try:
        vector = get_ollama_embedding(query)
        if not vector:
            return JsonResponse({'error': 'Failed to generate embedding'}, status=500)

        client = QdrantClient(host=qdrant_host, port=qdrant_port)
        search_result = client.search(
            collection_name=collection,
            query_vector=vector,
            limit=20
        )

        results = []
        for hit in search_result:
            p = hit.payload
            results.append({
                'id': p.get('id'),
                'type': 'post' if 'content' in p else 'link',
                'title': p.get('title'),
                'url': p.get('url'),
                'summary': p.get('description') or p.get('summary', ''),
                'score': hit.score,
                'tags': p.get('tags', [])
            })

        return JsonResponse({'results': results, 'total': len(results)})
    except Exception as e:
        logger.error(f"Vector search error: {e}")
        return JsonResponse({'error': str(e)}, status=500)

class SearchView(ListView):
    template_name = 'links/search.html'
    context_object_name = 'results'
    paginate_by = 20

    def get_queryset(self):
        query = self.request.GET.get('q', '').strip()
        type_filter = self.request.GET.get('type', '')
        sort_by = self.request.GET.get('sort', 'relevance')
        page_num = self.request.GET.get('page', 1)

        try:
            page_num = int(page_num)
        except (ValueError, TypeError):
            page_num = 1

        if query:
            try:
                search_results = search_backend.search(
                    query_string=query,
                    model_type=type_filter if type_filter else None,
                    page=page_num,
                    per_page=self.paginate_by,
                    sort_by=sort_by
                )

                enriched_results = []
                for result in search_results['results']:
                    enriched_result = self._enrich_result(result)
                    if enriched_result:
                        enriched_results.append(enriched_result)

                self.search_total = search_results['total']
                self.search_has_next = search_results['has_next']
                self.search_has_prev = search_results['has_prev']

                return enriched_results
            except Exception as e:
                logger.error(f"Search error: {e}", exc_info=True)
                self.search_error = str(e)
                return []
        return []

    def _enrich_result(self, result):
        model_type = result['model_type']
        model_id = result['model_id']
        try:
            if model_type == 'link':
                link = Link.objects.get(id=model_id)
                return {'id': link.id, 'model_type': 'link', 'alias': link.alias, 'original_url': link.original_url, 'description': link.description, 'click_count': link.click_count, 'created_at': link.created_at, 'tags': list(link.tags.all())}
            elif model_type == 'page':
                page = Page.objects.get(id=model_id)
                return {'id': page.id, 'model_type': 'page', 'title': page.title, 'url': page.url, 'summary': page.summary, 'created_at': page.created_at, 'tags': list(page.tags.all())}
            elif model_type == 'post':
                post = Post.objects.get(id=model_id)
                return {'id': post.id, 'model_type': 'post', 'title': post.title, 'summary': post.summary, 'created_at': post.created_at, 'tags': list(post.tags.all())}
        except Exception as e:
            logger.error(f"Error enriching result {model_type} {model_id}: {e}")
            return None

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({'query': self.request.GET.get('q', ''), 'selected_type': self.request.GET.get('type', ''), 'sort_by': self.request.GET.get('sort', 'relevance'), 'total_results': getattr(self, 'search_total', 0), 'search_error': getattr(self, 'search_error', None)})
        return context

def search(request):
    query = request.GET.get('q', '').strip()
    if query:
        results = []
        links = Link.objects.filter(Q(alias__icontains=query) | Q(original_url__icontains=query))[:5]
        results.extend([{'type': 'link', 'alias': link.alias, 'url': link.original_url} for link in links])
        posts = Post.objects.filter(Q(title__icontains=query) | Q(summary__icontains=query) | Q(content__icontains=query))[:5]
        results.extend([{'type': 'post', 'title': post.title, 'url': f'/ui/posts/{post.id}'} for post in posts])
    else:
        results = []
    return JsonResponse(results, safe=False)

@require_http_methods(["GET"])
def search_api_v2(request):
    query = request.GET.get('q', '').strip()
    type_filter = request.GET.get('type', '')
    sort_by = request.GET.get('sort', 'relevance')
    page = int(request.GET.get('page', 1))
    per_page = int(request.GET.get('per_page', 20))
    if not query:
        return JsonResponse({'results': [], 'total': 0, 'page': page, 'per_page': per_page, 'has_next': False, 'has_prev': False})

    cache_key = 'search:v2:' + hashlib.md5(
        f'{query}:{type_filter}:{sort_by}:{page}:{per_page}'.encode()
    ).hexdigest()
    cached = cache.get(cache_key)
    if cached is not None:
        return JsonResponse(cached)

    try:
        search_results = search_backend.search(query_string=query, model_type=type_filter if type_filter else None, page=page, per_page=per_page, sort_by=sort_by)
        enriched_results = []
        for result in search_results['results']:
            model_type = result['model_type']
            model_id = result['model_id']
            try:
                if model_type == 'link':
                    link = Link.objects.get(id=model_id)
                    enriched_results.append({'id': link.id, 'type': 'link', 'title': link.alias, 'url': f'/{link.alias}', 'original_url': link.original_url, 'description': link.description or '', 'click_count': link.click_count, 'created_at': link.created_at.isoformat(), 'tags': [{'id': tag.id, 'name': tag.name, 'slug': tag.slug} for tag in link.tags.all()]})
                elif model_type == 'page':
                    page_obj = Page.objects.get(id=model_id)
                    enriched_results.append({'id': page_obj.id, 'type': 'page', 'title': page_obj.title or 'Untitled', 'url': page_obj.url, 'detail_url': f'/ui/pages/{page_obj.id}/', 'summary': page_obj.summary or '', 'created_at': page_obj.created_at.isoformat(), 'tags': [{'id': tag.id, 'name': tag.name, 'slug': tag.slug} for tag in page_obj.tags.all()]})
                elif model_type == 'post':
                    post = Post.objects.get(id=model_id)
                    enriched_results.append({'id': post.id, 'type': 'post', 'title': post.title, 'url': f'/ui/posts/{post.id}/', 'summary': post.summary or '', 'created_at': post.created_at.isoformat(), 'tags': [{'id': tag.id, 'name': tag.name, 'slug': tag.slug} for tag in post.tags.all()]})
            except Exception as e:
                logger.error(f"Error enriching {model_type} {model_id}: {e}")
                continue
        result_payload = {'results': enriched_results, 'total': search_results['total'], 'page': search_results['page'], 'per_page': search_results['per_page'], 'has_next': search_results['has_next'], 'has_prev': search_results['has_prev']}
        cache.set(cache_key, result_payload, timeout=300)
        return JsonResponse(result_payload)
    except Exception as e:
        logger.error(f"Search API error: {e}", exc_info=True)
        return JsonResponse({'error': str(e), 'results': [], 'total': 0}, status=500)

def search_aliases(request):
    query = request.GET.get('q', '').strip()
    links = Link.objects.filter(alias__icontains=query).annotate(priority=Case(When(alias__iexact=query, then=Value(1)), When(alias__istartswith=query, then=Value(2)), default=Value(3), output_field=IntegerField())).order_by('priority', 'alias')[:10]
    results = []
    for link in links:
        try:
            url = request.build_absolute_uri(f'/{link.alias}/')
            results.append({'alias': link.alias, 'url': url})
        except Exception as e:
            logger.error(f"Error creating URL for alias {link.alias}: {str(e)}")
            continue
    return JsonResponse(results, safe=False)

class SearchReactView(TemplateView):
    template_name = 'links/search_react.html'
