import re

from apps.content.models.search_history import SearchHistory
from apps.core.models import SearchConfig
from apps.core.models.sensitive_config import SensitiveConfig
from apps.core.utils.sensitive_filter import SensitiveFilter
from django.apps import apps
from django.conf import settings
from django.db import IntegrityError, models
from django.db.models import Q
from django.http import JsonResponse
from django.views.decorators.http import require_GET
from django.views.generic import TemplateView


class SearchView(TemplateView):

    def get_template_names(self):
        theme = settings.THEME_NAME
        templates = [
            f"themes/{theme}/templates/search/results.html",
            "themes/default/templates/search/results.html"
        ]
        return templates

    def split_query(self, query):
        """搜索引擎式拆词逻辑"""
        # 1. 按空格拆分基础词
        base_words = re.split(r'\s+', query.strip())

        # 2. 提取带引号的短语
        phrases = re.findall(r'\"(.+?)\"', query)

        # 3. 合并结果并去重
        terms = list(set(base_words + phrases))

        # 4. 过滤空词
        return [term for term in terms if term]

    def build_dynamic_query(self, fields, query, search_engine=False):
        q_objects = Q()
        if search_engine:
            terms = self.split_query(query)

            for term in terms:
                term_q = Q()
                for field in fields:
                    term_q |= (Q(**{f"{field}__icontains": term})
                               & Q(**{f"{field}__isnull": False}))
                q_objects &= term_q
        else:
            for field in fields:
                q_objects |= (Q(**{f"{field}__icontains": query})
                              & Q(**{f"{field}__isnull": False}))

        return q_objects

        # return q_objects

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        query = self.request.GET.get('key', '')
        # 判断搜索词敏感不：
        sensitive_config = SensitiveConfig.get_solo()
        if sensitive_config.filter_switch:
            sensitive_manager = SensitiveFilter(sensitive_config)
            sensitive_bool = sensitive_manager.has_sensitive_words(query)
            if sensitive_bool:
                context.update({'sensitive': True})
                return context

        model_path = self.request.GET.get('model_path')
        search_config = SearchConfig.objects.first()
        if search_config.update_switch:
            created, search_obj = self.create_unique_search_history(query)
            context.update({
                'created': created,
                'search_obj': search_obj,
            })

        # 处理指定模型路径的情况
        if model_path:
            try:
                app_label, model_name = model_path.split('.')
                model = apps.get_model(app_label, model_name)
                fields = (search_config.content_fields if model_path
                          in getattr(search_config, 'content_models', []) else
                          search_config.user_space_search.get(model_path, []))

                q_objects = self.build_dynamic_query(
                    fields, query, search_config.search_engine)
                results11 = model.objects.filter(q_objects).only(
                    'title', 'meta_description', 'update_time')[:11]
                results = results11[:10]

                context.update({
                    'query': query,
                    'content_results': {
                        model_path: {
                            'verbose_name': model._meta.verbose_name,
                            'results': results,
                            'more': len(results11) > 10
                        }
                    },
                    'has_results': bool(results)
                })
                return context
            except Exception:
                pass

        # 原多模型查询逻辑
        content_results, user_results = self._search_multiple_models(
            search_config, query)

        context.update({
            'query': query,
            'content_results': content_results,
            'user_results': user_results,
            'has_results': bool(content_results or user_results)
        })
        return context

    def create_unique_search_history(self, title):
        """
        根据title创建不重复的搜索历史记录
        参数:
            title: 要创建的记录标题
        返回:
            tuple: (created: bool, obj: SearchHistory)
        """
        try:
            obj, created = SearchHistory.objects.get_or_create(
                title=title,
                defaults={
                    'py_title': '',  # 可根据需要填充拼音
                    'content': '',  # 默认空内容
                    'status': SearchHistory.StatusChoices.REVIEW
                })
            return (created, obj)
        except IntegrityError:
            # 处理并发创建冲突
            existing = SearchHistory.objects.filter(title=title).first()
            return (False, existing) if existing else (False, None)

    def _search_multiple_models(self, search_config, query):
        content_results = {}
        if search_config and search_config.content_models:
            for model_path in search_config.content_models:
                self._process_model(model_path, search_config.content_fields,
                                    query, content_results)

        user_results = {}
        if search_config and search_config.user_space_search:
            user_results = self._process_user_space_search(
                search_config, query)

        return content_results, user_results

    def _process_model(self, model_path, fields, query, results_dict):
        try:
            app_label, model_name = model_path.split('.')
            model = apps.get_model(app_label, model_name)
            q_objects = self.build_dynamic_query(fields, query)
            results11 = model.objects.filter(q_objects).only(
                'title', 'meta_description', 'update_time')[:11]
            results = results11[:10]
            if results:
                results_dict[model_path] = {
                    'verbose_name': model._meta.verbose_name,
                    'results': results,
                    'more': len(results11) > 10
                }
        except Exception:
            pass

    def _process_user_space_search(self, search_config, query):
        results = {}
        if not (search_config
                and getattr(search_config, 'user_space_search', None)):
            return results

        for model_path, config in search_config.user_space_search.items():
            try:
                app_label, model_name = model_path.split('.')
                model = apps.get_model(app_label, model_name)

                # 新版配置结构解析
                search_fields = config.get('search_fields', [])
                display_fields = config.get('display_fields', ['title'])
                limit = 10

                q_objects = self.build_dynamic_query(search_fields, query)
                queryset = model.objects.filter(q_objects)
                results_full = queryset.only(*display_fields)[:limit + 1]
                if results_full:
                    results[model_path] = {
                        'verbose_name': model._meta.verbose_name,
                        'results': results_full[:limit],
                        'more': len(results_full) > limit,
                        'fields': display_fields  # 前端可用的字段白名单
                    }
            except Exception as e:
                print(f"User space search error: {str(e)}")
        return results


@require_GET
def increment_search_hits(request):
    try:
        obj_id = request.GET.get('id')
        if not obj_id:
            return JsonResponse({'error': 'Missing id parameter'}, status=400)

        record = SearchHistory.objects.get(pk=obj_id)
        record.hits = models.F('hits') + 1  # 原子操作避免并发问题
        record.save(update_fields=['hits'])
        record.refresh_from_db()  # 从数据库重新加载最新值

        return JsonResponse({'id': record.id, 'hits': record.hits})

    except SearchHistory.DoesNotExist:
        return JsonResponse({'error': 'Record not found'}, status=404)
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)
