"""
dashboard.py

This module is used to write dashboard related views
"""

import datetime

from django.core import serializers
from django.http import JsonResponse
from django.shortcuts import render
from django.utils.translation import gettext_lazy as _

from base.models import Department, JobPosition
from employee.models import EmployeeWorkInformation
from horilla.decorators import login_required
from recruitment.decorators import manager_can_enter
from recruitment.models import Candidate, Recruitment, SkillZone, Stage


def stage_type_candidate_count(rec, stage_type):
    """
    This method is used find the count of candidate in recruitment
    """
    candidates_count = 0
    for stage_obj in rec.stage_set.filter(stage_type=stage_type):
        candidates_count = candidates_count + len(
            stage_obj.candidate_set.filter(is_active=True)
        )
    return candidates_count


@login_required
@manager_can_enter(perm="recruitment.view_recruitment")
def dashboard(request):
    """
    This method is used to render dashboard for recruitment module
    """
    candidates = Candidate.objects.all()
    stage_chart_count = 0
    vacancy_chart = Recruitment.objects.filter(closed=False, is_event_based=False)
    if vacancy_chart.exists():
        dep_vacancy = 1
    else:
        dep_vacancy = 0
    employee_info = EmployeeWorkInformation.objects.all()
    joining_list = []
    for rec in employee_info:
        if rec.date_joining != None:
            joining_list.append("OK")
    if joining_list != []:
        joining = 1
    else:
        joining = 0

    jobs = JobPosition.objects.all()
    all_job = []
    for job in jobs:
        jobpos = job.job_position
        all_job.append(jobpos)

    initial = []
    for job in jobs:
        ini = Candidate.objects.filter(
            job_position_id=job, stage_id__stage_type="initial"
        )
        initial.append(ini.count())

    test = []
    for job in jobs:
        tes = Candidate.objects.filter(job_position_id=job, stage_id__stage_type="test")
        test.append(tes.count())

    interview = []
    for job in jobs:
        inter = Candidate.objects.filter(
            job_position_id=job, stage_id__stage_type="interview"
        )
        interview.append(inter.count())

    hired = []
    for job in jobs:
        hire = Candidate.objects.filter(
            job_position_id=job, stage_id__stage_type="hired"
        )
        hired.append(hire.count())
    cancelled = []
    for job in jobs:
        cancelled_candidates = Candidate.objects.filter(
            job_position_id=job, stage_id__stage_type="cancelled"
        )
        cancelled.append(cancelled_candidates.count())

    job_data = list(zip(all_job, initial, test, interview, hired, cancelled))

    recruitment_obj = Recruitment.objects.filter(closed=False)
    ongoing_recruitments = len(recruitment_obj)

    for rec in recruitment_obj:
        data = [stage_type_candidate_count(rec, type[0]) for type in Stage.stage_types]
        for i in data:
            stage_chart_count += i

        if stage_chart_count >= 1:
            stage_chart_count = 1

    onboarding_count = Candidate.objects.filter(start_onboard=True)
    onboarding_count = onboarding_count.count()

    recruitment_manager_mapping = {}

    for rec in recruitment_obj:
        recruitment_title = rec.title
        managers = []

        for manager in rec.recruitment_managers.all():
            name = manager.get_full_name()
            managers.append(name)

        recruitment_manager_mapping[recruitment_title] = managers

    total_vacancy = 0
    for openings in recruitment_obj:
        if openings.vacancy == None:
            pass
        else:
            total_vacancy += openings.vacancy

    hired_candidates = candidates.filter(hired=True)
    total_candidates = len(candidates)
    total_hired_candidates = len(hired_candidates)
    conversion_ratio = 0
    hired_ratio = 0
    total_candidate_ratio = 0
    acceptance_ratio = 0
    if total_candidates != 0:
        conversion_ratio = f"{((total_hired_candidates / total_candidates) * 100):.1f}"
    if total_vacancy != 0:
        hired_ratio = f"{((total_hired_candidates / total_vacancy) * 100):.1f}"
        total_candidate_ratio = f"{((total_candidates / total_vacancy) * 100):.1f}"
    if total_hired_candidates != 0:
        acceptance_ratio = f"{((onboarding_count / total_hired_candidates) * 100):.1f}"

    skill_zone = SkillZone.objects.filter(is_active=True)
    return render(
        request,
        "dashboard/dashboard.html",
        {
            "ongoing_recruitments": ongoing_recruitments,
            "total_candidate_ratio": total_candidate_ratio,
            "total_hired_candidates": total_hired_candidates,
            "conversion_ratio": conversion_ratio,
            "acceptance_ratio": acceptance_ratio,
            "onboard_candidates": hired_candidates.filter(start_onboard=True),
            "job_data": job_data,
            "total_vacancy": total_vacancy,
            "recruitment_manager_mapping": recruitment_manager_mapping,
            "hired_ratio": hired_ratio,
            "joining": joining,
            "dep_vacancy": dep_vacancy,
            "stage_chart_count": stage_chart_count,
            "onboarding_count": onboarding_count,
            "total_candidates": total_candidates,
            "skill_zone": skill_zone,
        },
    )


@login_required
@manager_can_enter(perm="recruitment.view_recruitment")
def dashboard_pipeline(request):
    """
    This method is used generate recruitment dataset for the dashboard
    """
    recruitment_obj = Recruitment.objects.filter(closed=False)
    data_set = []
    labels = [type[1] for type in Stage.stage_types]
    for rec in recruitment_obj:
        data = [stage_type_candidate_count(rec, type[0]) for type in Stage.stage_types]
        if rec.candidate.all():
            data_set.append(
                {
                    "label": (
                        rec.title
                        if rec.title is not None
                        else f"""{rec.job_position_id}
                    {rec.start_date}"""
                    ),
                    "data": data,
                }
            )
    return JsonResponse(
        {"dataSet": data_set, "labels": labels, "message": _("No data Found...")}
    )


@login_required
@manager_can_enter(perm="recruitment.view_recruitment")
def dashboard_hiring(request):
    """
    This method is used generate employee joining status for the dashboard
    """

    selected_year = request.GET.get("id")

    employee_info = EmployeeWorkInformation.objects.filter(
        date_joining__year=selected_year
    )

    # Create a list to store the count of employees for each month
    employee_count_per_month = [0] * 12  # Initialize with zeros for all months

    # Count the number of employees who joined in each month for the selected year
    for info in employee_info:
        if isinstance(info.date_joining, datetime.date):
            month_index = info.date_joining.month - 1  # Month index is zero-based
            employee_count_per_month[
                month_index
            ] += 1  # Increment the count for the corresponding month

    labels = [
        _("January"),
        _("February"),
        _("March"),
        _("April"),
        _("May"),
        _("June"),
        _("July"),
        _("August"),
        _("September"),
        _("October"),
        _("November"),
        _("December"),
    ]

    data_set = [
        {
            "label": _("Employees joined in %(year)s") % {"year": selected_year},
            "data": employee_count_per_month,
            "backgroundColor": "rgba(236, 131, 25)",
        }
    ]

    return JsonResponse({"dataSet": data_set, "labels": labels})


@login_required
@manager_can_enter(perm="recruitment.view_recruitment")
def dashboard_vacancy(_request):
    """
    This method is used to generate a recruitment vacancy chart for the dashboard
    """

    recruitment_obj = Recruitment.objects.filter(closed=False, is_event_based=False)
    department = Department.objects.all()
    label = []
    data_set = [{"label": _("Openings"), "data": []}]

    for dep in department:
        vacancies_for_department = recruitment_obj.filter(
            job_position_id__department_id=dep
        )
        for rec in vacancies_for_department:
            if rec.vacancy is not None:
                label.append(dep.department)

        vacancies = [
            int(rec.vacancy) if rec.vacancy is not None else 0
            for rec in vacancies_for_department
        ]

        data_set[0]["data"].append([sum(vacancies)])

    return JsonResponse({"dataSet": data_set, "labels": label})


def get_open_position(request):
    """
    This is an ajax method to render the open position to the recruitment

    Returns:
        obj: it returns the list of job positions
    """
    rec_id = request.GET["recId"]
    recruitment_obj = Recruitment.objects.get(id=rec_id)
    queryset = recruitment_obj.open_positions.all()
    job_info = serializers.serialize("json", queryset)
    rec_info = serializers.serialize("json", [recruitment_obj])
    return JsonResponse({"openPositions": job_info, "recruitmentInfo": rec_info})


@login_required
@manager_can_enter(perm="recruitment.view_recruitment")
def candidate_status(_request):
    """
    This method is used to generate a CAndidate status chart for the dashboard
    """

    not_sent_candidates = Candidate.objects.filter(
        offer_letter_status="not_sent"
    ).count()
    sent_candidates = Candidate.objects.filter(offer_letter_status="sent").count()
    accepted_candidates = Candidate.objects.filter(
        offer_letter_status="accepted"
    ).count()
    rejected_candidates = Candidate.objects.filter(
        offer_letter_status="rejected"
    ).count()
    joined_candidates = Candidate.objects.filter(offer_letter_status="joined").count()

    data_set = []
    labels = ["Not Sent", "Sent", "Accepted", "Rejected", "Joined"]
    data = [
        not_sent_candidates,
        sent_candidates,
        accepted_candidates,
        rejected_candidates,
        joined_candidates,
    ]

    for i in range(len(data)):

        data_set.append({"label": labels[i], "data": data[i]})

    # for i in range(len(data)):
    #     if data[i] != 0:
    #         data_set.append({
    #             "label": labels[i],
    #             "data": data[i]
    #         })

    # # Remove labels corresponding to data points with value 0
    # labels = [label for label, d in zip(labels, data) if d != 0]

    return JsonResponse({"dataSet": data_set, "labels": labels})
