from django.db.models import Case, Count, IntegerField, Q, Value, When
from django.shortcuts import render

from accounts.visibility import get_visible_company_or_404, visible_companies
from home.pagination import paginate
from jobs.models import Job
from jobs.status import open_jobs_q

from .follow_views import user_follows_company
from .forms import CompanyFilterForm
from .models import Company


def _apply_open_jobs_count(companies):
    """Attach open_jobs_count from Job model via company_slug match."""
    companies = list(companies)
    slugs = [company.slug for company in companies]
    counts = {
        row['company_slug']: row['total']
        for row in Job.objects.filter(open_jobs_q(), company_slug__in=slugs)
        .values('company_slug')
        .annotate(total=Count('id'))
    }
    result = []
    for company in companies:
        company.open_jobs_count = counts.get(company.slug, 0)
        result.append(company)
    return result


def _filter_companies(queryset, form):
    q = form.cleaned_data.get('q')
    location = form.cleaned_data.get('location')
    industries = form.cleaned_data.get('industry')
    sizes = form.cleaned_data.get('company_size')
    tiers = form.cleaned_data.get('tier')
    sort = form.cleaned_data.get('sort') or 'featured'

    if q:
        queryset = queryset.filter(
            Q(name__icontains=q) | Q(industry__icontains=q) | Q(short_description__icontains=q) | Q(description__icontains=q)
        )
    if location:
        queryset = queryset.filter(location__icontains=location)
    if industries:
        queryset = queryset.filter(industry_slug__in=industries)
    for field in ('country', 'province', 'city'):
        value = form.cleaned_data.get(field)
        if value:
            queryset = queryset.filter(**{f'{field}__iexact': value})
    company_type = form.cleaned_data.get('company_type')
    if company_type:
        queryset = queryset.filter(company_type=company_type)
    hiring = form.cleaned_data.get('hiring') or []
    if len(hiring) == 1:
        hiring_slugs = Job.objects.filter(open_jobs_q()).exclude(company_slug='').values('company_slug')
        queryset = queryset.filter(slug__in=hiring_slugs) if hiring == ['yes'] else queryset.exclude(slug__in=hiring_slugs)
    if form.cleaned_data.get('verified'):
        queryset = queryset.exclude(registered_name='').exclude(registration_number='')
    if sizes:
        queryset = queryset.filter(company_size__in=sizes)
    if tiers:
        queryset = queryset.filter(tier__in=tiers)

    if sort == 'name':
        queryset = queryset.order_by('name')
    elif sort == 'newest':
        queryset = queryset.order_by('-created_at')
    else:
        # Relevance: fuller profiles (cover, blurb, tags) first, then featured / tier / name.
        completeness = (
            Case(When(~Q(cover_image_url=''), then=Value(1)), default=Value(0), output_field=IntegerField())
            + Case(When(~Q(short_description=''), then=Value(1)), default=Value(0), output_field=IntegerField())
            + Case(When(~Q(tags=''), then=Value(1)), default=Value(0), output_field=IntegerField())
        )
        queryset = queryset.annotate(_completeness=completeness).order_by('-_completeness', '-is_featured', '-tier', 'name')

    return queryset


def company_list(request):
    queryset = visible_companies()
    industry_choices = (
        visible_companies()
        .values_list('industry_slug', 'industry')
        .distinct()
        .order_by('industry')
    )
    form = CompanyFilterForm(request.GET, industry_choices=industry_choices)

    if form.is_valid():
        queryset = _filter_companies(queryset, form)

    sort = form.cleaned_data.get('sort') if form.is_valid() else 'featured'
    if sort == 'jobs':
        companies_list = _apply_open_jobs_count(list(queryset))
        companies_list.sort(key=lambda c: c.open_jobs_count, reverse=True)
        page_obj, query_string, page_range = paginate(request, companies_list, per_page=12)
        companies = page_obj.object_list
        total_count = len(companies_list)
    else:
        page_obj, query_string, page_range = paginate(request, queryset, per_page=12)
        companies = _apply_open_jobs_count(page_obj.object_list)
        total_count = page_obj.paginator.count

    industry_filters = [
        {'value': slug, 'label': label, 'count': visible_companies().filter(industry_slug=slug).count()}
        for slug, label in industry_choices
    ]
    size_filters = [
        {
            'value': choice[0],
            'label': choice[1],
            'count': visible_companies().filter(company_size=choice[0]).count(),
        }
        for choice in Company.Size.choices
    ]
    tier_filters = [
        {
            'value': choice[0],
            'label': choice[1],
            'count': visible_companies().filter(tier=choice[0]).count(),
        }
        for choice in Company.Tier.choices
    ]

    def _distinct(field):
        seen = {}
        for v in visible_companies().values_list(field, flat=True):
            if v and v.strip():
                seen.setdefault(v.strip().lower(), v.strip().title() if v.strip().islower() else v.strip())
        return sorted(seen.values(), key=str.lower)

    context = {
        'country_options': _distinct('country'),
        'province_options': _distinct('province'),
        'city_options': _distinct('city'),
        'companies': companies,
        'form': form,
        'page_obj': page_obj,
        'query_string': query_string,
        'page_range': page_range,
        'total_count': total_count,
        'industry_filters': industry_filters,
        'size_filters': size_filters,
        'tier_filters': tier_filters,
    }
    return render(request, 'companies/list.html', context)


def company_detail(request, slug):
    company = get_visible_company_or_404(request, slug)
    open_jobs = Job.objects.filter(open_jobs_q(), company_slug=company.slug).select_related('category')
    open_jobs_count = open_jobs.count()

    context = {
        'company': company,
        'open_jobs': open_jobs,
        'company_products': company.products.all(),
        'company_photos': company.photos.all(),
        'open_jobs_count': open_jobs_count,
        'is_following_company': user_follows_company(request.user, company),
        'can_follow_company': request.user.is_authenticated and request.user.is_seeker,
    }
    return render(request, 'companies/detail.html', context)
