from decimal import Decimal

from django.utils import timezone
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import serializers as drf_serializers

from api.models.data.currency import BASE_CURRENCY_ID, get_currency
from api.models.data.employee import Employee
from api.serializers.data.employee import EmployeeSerializer
from api.services.employee_account import create_user_for_employee
from api.utils.currency import convert_currency
from api.views.data.base import DataRootViewSet


def _d(value):
    return Decimal(str(value or 0))


class EmployeeViewSet(DataRootViewSet):
    permission_module = 'employees'
    permission_action_map = {
        'create_account': ['add_users', 'edit_employees'],
    }
    serializer_class = EmployeeSerializer
    search_fields = ["full_name", "email", "phone", "tazkira_number"]
    queryset = Employee.objects.all().order_by("-id")

    def _summary_for_employee(self, employee, month=None, year=None, target_currency_id=None):
        # Use employee's currency, or target, or base (AFN)
        employee_currency_id = target_currency_id or employee.currency or BASE_CURRENCY_ID

        payrolls = employee.payrolls.all()
        if month:
            payrolls = payrolls.filter(month=month)
        if year:
            payrolls = payrolls.filter(year=int(year))

        salary_paid = Decimal('0.00')
        advance_paid = Decimal('0.00')
        for payroll in payrolls:
            payroll_currency_id = payroll.currency or BASE_CURRENCY_ID
            converted_amount = convert_currency(
                payroll.amount or payroll.net_salary,
                payroll_currency_id,
                employee_currency_id,
                payroll.payment_date or timezone.now(),
            )
            amount = Decimal(str(converted_amount))
            if payroll.payroll_type == 'advance':
                advance_paid += amount
            else:
                salary_paid += amount

        monthly_salary = _d(employee.salary)
        total_against_salary = salary_paid + advance_paid
        salary_remaining = monthly_salary - salary_paid
        total_remaining = monthly_salary - total_against_salary
        total_paid = salary_paid + advance_paid

        c = get_currency(employee_currency_id)
        return {
            'salary': float(monthly_salary),
            'paid_salary': float(salary_paid),
            'paid_advance': float(advance_paid),
            'total_paid': float(total_paid),
            'salary_remaining': float(salary_remaining),
            'total_remaining': float(total_remaining),
            'currency': {
                'id': employee_currency_id,
                'code': c['code'],
                'symbol': c['symbol'],
                'name': c['name'],
            } if c else None,
            'month': month,
            'year': int(year) if year else None,
        }

    def list(self, request, *args, **kwargs):
        response = super().list(request, *args, **kwargs)
        month = request.query_params.get('month')
        year = request.query_params.get('year')
        currency_id = request.query_params.get('summary_currency')
        target_currency_id = int(currency_id) if currency_id and currency_id.isdigit() else None

        payload = response.data
        rows = payload.get('results', payload) if isinstance(payload, dict) else payload
        if isinstance(rows, list):
            employee_map = {
                str(emp.id): emp
                for emp in Employee.objects.filter(id__in=[row.get('id') for row in rows if row.get('id')])
            }
            for row in rows:
                employee = employee_map.get(str(row.get('id')))
                if not employee:
                    continue
                row['payment_summary'] = self._summary_for_employee(
                    employee, month=month, year=year, target_currency_id=target_currency_id
                )
        return response

    @action(detail=True, methods=['get'])
    def financial_summary(self, request, pk=None):
        employee = self.get_object()
        month = request.query_params.get('month')
        year = request.query_params.get('year')
        currency_id = request.query_params.get('currency')
        target_currency_id = int(currency_id) if currency_id and currency_id.isdigit() else None
        return Response(self._summary_for_employee(
            employee, month=month, year=year, target_currency_id=target_currency_id
        ))

    @action(detail=True, methods=['post'], url_path='create-account')
    def create_account(self, request, pk=None):
        employee = self.get_object()
        password = request.data.get('account_password') or request.data.get('password') or ''
        email = request.data.get('account_email') or request.data.get('email') or employee.email or ''
        try:
            create_user_for_employee(
                employee,
                email=email,
                password=password,
                actor=request.user,
            )
        except drf_serializers.ValidationError as exc:
            return Response(exc.detail, status=status.HTTP_400_BAD_REQUEST)
        employee.refresh_from_db()
        return Response(self.get_serializer(employee).data, status=status.HTTP_201_CREATED)
