import secrets

from django.contrib.auth import get_user_model
from django.db import transaction
from django.db.models import Q
from rest_framework import status
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from users.models import CompanyUser
from documents.models import DocumentRecord, EmployeeDocument

from .models import EmployeeSection, EmployeeSectionResponse, FieldOption, SectionField
from .serializers import (
    CompanyCreateSerializer,
    CompanyEmployeeReadSerializer,
    CompanyUserUpdateSerializer,
    InviteEmployeesBulkSerializer,
    TerminateEmployeeItemSerializer,
    TerminateEmployeesBulkSerializer,
)


RELATIONSHIP_OPTIONS = [
    'Father',
    'Mother',
    'Brother',
    'Sister',
    'Cousin',
    'Friend',
]

User = get_user_model()


class CompanyCreateView(APIView):
    permission_classes = [IsAuthenticated]

    @transaction.atomic
    def post(self, request):
        serializer = CompanyCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        company = serializer.save()

        CompanyUser.objects.create(
            user=request.user,
            company=company,
            employment_number=self._generate_employment_number(),
            user_type=CompanyUser.UserType.ADMIN,
            work_email_address=request.user.email or None,
            status=CompanyUser.Status.ACTIVE,
        )

        self._seed_default_employee_sections(company)

        return Response(
            {
                'company': CompanyCreateSerializer(company).data,
                'detail': 'Company created. Default sections and fields generated.',
            },
            status=status.HTTP_201_CREATED,
        )

    def _generate_employment_number(self):
        while True:
            candidate = f"EMP-{secrets.token_hex(4).upper()}"
            if not CompanyUser.objects.filter(employment_number=candidate).exists():
                return candidate

    def _create_field(self, section, name, label, data_type, is_required=False, options=None, max_length=None):
        field = SectionField.objects.create(
            employee_section=section,
            name=name,
            label=label,
            data_type=data_type,
            is_required=is_required,
            is_system_default=True,
            status=SectionField.Status.ACTIVE,
            max_length=max_length,
        )

        for option in options or []:
            FieldOption.objects.create(
                section_field=field,
                name=option.lower().replace(' ', '_').replace('+', 'plus'),
                label=option,
                value=option,
                status=FieldOption.Status.ACTIVE,
            )

        return field

    def _seed_default_employee_sections(self, company):
        contact_info = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.PERSONAL,
            name='Contact Information',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        self._create_field(
            contact_info,
            name='home_address',
            label='Home Address',
            data_type=SectionField.DataType.TEXTAREA,
            is_required=True,
        )
        self._create_field(
            contact_info,
            name='work_email_address',
            label='Work Email Address',
            data_type=SectionField.DataType.EMAIL,
            is_required=True,
        )

        demographics = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.PERSONAL,
            name='Demographics',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        self._create_field(
            demographics,
            name='pronouns',
            label='Pronouns',
            data_type=SectionField.DataType.SELECT,
            options=['Mr', 'Mrs', 'Miss', 'Dr', 'Engr'],
        )
        self._create_field(
            demographics,
            name='date_of_birth',
            label='Date of Birth',
            data_type=SectionField.DataType.DATE,
            is_required=True,
        )
        self._create_field(
            demographics,
            name='nationality',
            label='Nationality',
            data_type=SectionField.DataType.TEXT,
        )

        emergency_contact = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.PERSONAL,
            name='Emergency Contact',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        contact_1 = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.PERSONAL,
            parent_id=emergency_contact,
            name='Contact 1',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        self._create_field(
            contact_1,
            name='name',
            label='Name',
            data_type=SectionField.DataType.TEXT,
        )
        self._create_field(
            contact_1,
            name='phone',
            label='Phone',
            data_type=SectionField.DataType.TEXT,
            max_length=15,
        )
        self._create_field(
            contact_1,
            name='relationship',
            label='Relationship',
            data_type=SectionField.DataType.SELECT,
            options=RELATIONSHIP_OPTIONS,
        )

        contact_2 = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.PERSONAL,
            parent_id=emergency_contact,
            name='Contact 2',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        self._create_field(
            contact_2,
            name='name',
            label='Name',
            data_type=SectionField.DataType.TEXT,
        )
        self._create_field(
            contact_2,
            name='phone',
            label='Phone',
            data_type=SectionField.DataType.TEXT,
            max_length=15,
        )
        self._create_field(
            contact_2,
            name='relationship',
            label='Relationship',
            data_type=SectionField.DataType.SELECT,
            options=RELATIONSHIP_OPTIONS,
        )

        employment_information = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.EMPLOYMENT,
            name='Employment Information',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        self._create_field(
            employment_information,
            name='job_title',
            label='Job Title',
            data_type=SectionField.DataType.TEXT,
            is_required=True,
        )
        self._create_field(
            employment_information,
            name='department',
            label='Department',
            data_type=SectionField.DataType.TEXT,
        )
        self._create_field(
            employment_information,
            name='wage_type',
            label='Wage Type',
            data_type=SectionField.DataType.SELECT,
            options=['Flat', 'Commission', 'Flat + Commission'],
        )
        self._create_field(
            employment_information,
            name='location',
            label='Location',
            data_type=SectionField.DataType.SELECT,
            options=['Remote', 'On site', 'Hybrid'],
        )

        tenure_information = EmployeeSection.objects.create(
            company=company,
            section_class=EmployeeSection.SectionClass.EMPLOYMENT,
            name='Tenure Information',
            status=EmployeeSection.Status.ACTIVE,
            is_visible=True,
            is_system_default=True,
        )

        self._create_field(
            tenure_information,
            name='employment_type',
            label='Employment Type',
            data_type=SectionField.DataType.SELECT,
            options=['Full Time', 'Part Time', 'Contract'],
        )
        self._create_field(
            tenure_information,
            name='probation_end_date',
            label='Probation End Date',
            data_type=SectionField.DataType.DATE,
        )


class CompanyUserUpdateView(APIView):
    permission_classes = [IsAuthenticated]

    @transaction.atomic
    def patch(self, request, company_id, company_user_id):
        return self._update(request, company_id, company_user_id, partial=True)

    @transaction.atomic
    def put(self, request, company_id, company_user_id):
        return self._update(request, company_id, company_user_id, partial=False)

    def _update(self, request, company_id, company_user_id, partial):
        target_company_user = CompanyUser.objects.filter(
            id=company_user_id,
            company_id=company_id,
        ).select_related('company', 'user').first()

        if not target_company_user:
            return Response({'detail': 'Company user not found.'}, status=status.HTTP_404_NOT_FOUND)

        actor_membership = CompanyUser.objects.filter(
            company_id=company_id,
            user=request.user,
            status=CompanyUser.Status.ACTIVE,
        ).first()

        if not actor_membership or actor_membership.user_type != CompanyUser.UserType.ADMIN:
            return Response(
                {'detail': 'Only active company admins can update employee records.'},
                status=status.HTTP_403_FORBIDDEN,
            )

        serializer = CompanyUserUpdateSerializer(
            target_company_user,
            data=request.data,
            partial=partial,
            context={'company': target_company_user.company},
        )
        serializer.is_valid(raise_exception=True)
        updated = serializer.save()

        return Response(
            {
                'id': updated.id,
                'user_id': updated.user_id,
                'company_id': updated.company_id,
                'employment_number': updated.employment_number,
                'work_email_address': updated.work_email_address,
                'phone_number': updated.phone_number,
                'profile_pic': str(updated.profile_pic) if updated.profile_pic else None,
                'status': updated.status,
                'start_date': updated.start_date,
            },
            status=status.HTTP_200_OK,
        )


class CompanyEmployeesPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100


class CompanyEmployeesListView(APIView):
    permission_classes = [IsAuthenticated]
    pagination_class = CompanyEmployeesPagination

    def get(self, request, company_id):
        actor_membership = CompanyUser.objects.filter(
            company_id=company_id,
            user=request.user,
            status=CompanyUser.Status.ACTIVE,
        ).first()

        if not actor_membership:
            return Response(
                {'detail': 'You are not an active member of this company.'},
                status=status.HTTP_403_FORBIDDEN,
            )

        queryset = CompanyUser.objects.filter(company_id=company_id).select_related('user', 'company')

        search = request.query_params.get('search', '').strip()
        if search:
            queryset = queryset.filter(
                Q(user__first_name__icontains=search)
                | Q(user__last_name__icontains=search)
                | Q(user__username__icontains=search)
                | Q(user__email__icontains=search)
                | Q(employment_number__icontains=search)
                | Q(work_email_address__icontains=search)
                | Q(phone_number__icontains=search)
            )

        queryset = queryset.order_by('id')
        paginator = self.pagination_class()
        page = paginator.paginate_queryset(queryset, request)
        serializer = CompanyEmployeeReadSerializer(page, many=True)
        return paginator.get_paginated_response(serializer.data)


class CompanyEmployeeByNumberView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, company_id, employment_number):
        actor_membership = CompanyUser.objects.filter(
            company_id=company_id,
            user=request.user,
            status=CompanyUser.Status.ACTIVE,
        ).first()

        if not actor_membership:
            return Response(
                {'detail': 'You are not an active member of this company.'},
                status=status.HTTP_403_FORBIDDEN,
            )

        company_user = CompanyUser.objects.filter(
            company_id=company_id,
            employment_number=employment_number,
        ).select_related('user', 'company').first()

        if not company_user:
            return Response({'detail': 'Employee not found.'}, status=status.HTTP_404_NOT_FOUND)

        serializer = CompanyEmployeeReadSerializer(company_user)
        return Response(serializer.data, status=status.HTTP_200_OK)


class TerminateEmployeeView(APIView):
    permission_classes = [IsAuthenticated]

    @transaction.atomic
    def post(self, request):
        serializer = TerminateEmployeeItemSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        result = self._terminate_one(
            actor=request.user,
            user_id=serializer.validated_data['user_id'],
            company_id=serializer.validated_data['company_id'],
        )

        if not result['success']:
            status_code = result.pop('status_code')
            return Response(result, status=status_code)

        return Response(result, status=status.HTTP_200_OK)

    def _terminate_one(self, actor, user_id, company_id):
        actor_membership = CompanyUser.objects.filter(
            company_id=company_id,
            user=actor,
            status=CompanyUser.Status.ACTIVE,
            user_type=CompanyUser.UserType.ADMIN,
        ).first()

        if not actor_membership:
            return {
                'success': False,
                'status_code': status.HTTP_403_FORBIDDEN,
                'detail': 'Only active company admins can terminate employees.',
            }

        target = CompanyUser.objects.filter(company_id=company_id, user_id=user_id).first()
        if not target:
            return {
                'success': False,
                'status_code': status.HTTP_404_NOT_FOUND,
                'detail': 'Employee membership not found for this company.',
            }

        if target.status == CompanyUser.Status.INACTIVE:
            return {
                'success': True,
                'detail': 'Employee is already inactive.',
                'company_user_id': target.id,
                'company_id': company_id,
                'user_id': user_id,
                'status': target.status,
            }

        target.status = CompanyUser.Status.INACTIVE
        target.save(update_fields=['status', 'last_updated'])

        return {
            'success': True,
            'detail': 'Employee terminated successfully.',
            'company_user_id': target.id,
            'company_id': company_id,
            'user_id': user_id,
            'status': target.status,
        }


class TerminateEmployeesBulkView(TerminateEmployeeView):
    permission_classes = [IsAuthenticated]

    @transaction.atomic
    def post(self, request):
        data = request.data
        if isinstance(data, list):
            payload = {'employees': data}
        else:
            payload = data

        serializer = TerminateEmployeesBulkSerializer(data=payload)
        serializer.is_valid(raise_exception=True)

        terminated = []
        failed = []

        for item in serializer.validated_data['employees']:
            result = self._terminate_one(
                actor=request.user,
                user_id=item['user_id'],
                company_id=item['company_id'],
            )

            result_payload = {
                'company_id': item['company_id'],
                'user_id': item['user_id'],
                'detail': result.get('detail'),
            }

            if result['success']:
                result_payload['company_user_id'] = result.get('company_user_id')
                result_payload['status'] = result.get('status')
                terminated.append(result_payload)
            else:
                failed.append(result_payload)

        return Response(
            {
                'terminated_count': len(terminated),
                'failed_count': len(failed),
                'terminated': terminated,
                'failed': failed,
            },
            status=status.HTTP_200_OK,
        )


class InviteEmployeesBulkView(APIView):
    permission_classes = [IsAuthenticated]

    @transaction.atomic
    def post(self, request, company_id):
        actor_membership = CompanyUser.objects.filter(
            company_id=company_id,
            user=request.user,
            status=CompanyUser.Status.ACTIVE,
            user_type=CompanyUser.UserType.ADMIN,
        ).first()

        if not actor_membership:
            return Response(
                {'detail': 'Only active company admins can invite employees.'},
                status=status.HTTP_403_FORBIDDEN,
            )

        data = request.data
        if isinstance(data, list):
            payload = {'employees': data}
        else:
            payload = data

        serializer = InviteEmployeesBulkSerializer(data=payload)
        serializer.is_valid(raise_exception=True)

        section_fields = list(
            SectionField.objects.filter(
                employee_section__company_id=company_id,
                status=SectionField.Status.ACTIVE,
            ).select_related('employee_section')
        )

        invited = []
        failed = []

        for item in serializer.validated_data['employees']:
            result = self._invite_one(
                company_id=company_id,
                employee_data=item,
                section_fields=section_fields,
            )
            if result['success']:
                invited.append(result)
            else:
                failed.append(result)

        return Response(
            {
                'invited_count': len(invited),
                'failed_count': len(failed),
                'invited': invited,
                'failed': failed,
            },
            status=status.HTTP_200_OK,
        )

    def _invite_one(self, company_id, employee_data, section_fields):
        email = employee_data['email'].lower().strip()
        first_name = employee_data['first_name'].strip()
        last_name = employee_data['last_name'].strip()
        job_title = employee_data['job_title'].strip()

        user = User.objects.filter(email__iexact=email).first()
        if user is None:
            username = self._generate_username_from_email(email)
            user = User.objects.create_user(
                username=username,
                email=email,
                first_name=first_name,
                last_name=last_name,
            )
            user.set_unusable_password()
            user.save(update_fields=['password'])
        else:
            changed = False
            if user.first_name != first_name:
                user.first_name = first_name
                changed = True
            if user.last_name != last_name:
                user.last_name = last_name
                changed = True
            if changed:
                user.save(update_fields=['first_name', 'last_name'])

        company_user, created = CompanyUser.objects.get_or_create(
            company_id=company_id,
            user=user,
            defaults={
                'employment_number': self._generate_employment_number(),
                'user_type': CompanyUser.UserType.EMPLOYEE,
                'work_email_address': email,
                'status': CompanyUser.Status.BIO_REQUESTED,
            },
        )

        if not created and company_user.user_type != CompanyUser.UserType.EMPLOYEE:
            return {
                'success': False,
                'email': email,
                'detail': 'User already exists in this company as a non-employee member.',
            }

        for section_field in section_fields:
            default_response = job_title if section_field.name == 'job_title' else None
            EmployeeSectionResponse.objects.update_or_create(
                user=user,
                company_id=company_id,
                section_field=section_field,
                defaults={'response_value': default_response},
            )

        self._create_default_employee_documents(company_id=company_id, user=user)

        # Placeholder for outbound invite email integration.
        self._send_invitation_email(
            first_name=first_name,
            last_name=last_name,
            email=email,
            company_user=company_user,
        )

        return {
            'success': True,
            'detail': 'Employee invited successfully.',
            'user_id': user.id,
            'company_user_id': company_user.id,
            'email': email,
            'employment_number': company_user.employment_number,
            'created': created,
        }

    def _generate_username_from_email(self, email):
        base = email.split('@')[0].strip().replace(' ', '').lower() or 'user'
        candidate = base
        while User.objects.filter(username=candidate).exists():
            candidate = f"{base}{secrets.token_hex(2)}"
        return candidate

    def _generate_employment_number(self):
        while True:
            candidate = f"EMP-{secrets.token_hex(4).upper()}"
            if not CompanyUser.objects.filter(employment_number=candidate).exists():
                return candidate

    def _send_invitation_email(self, first_name, last_name, email, company_user):
        # TODO: Integrate with your email provider here.
        # Suggested payload: recipient email, employee first/last name, employment number,
        # invite link, and onboarding instructions.
        return

    def _create_default_employee_documents(self, company_id, user):
        defaults = [
            {'name': 'NIN', 'description': 'National Identification Number document', 'is_required': True, 'sort_id': 1},
            {'name': 'School Cert', 'description': 'School certificate document', 'is_required': False, 'sort_id': 2},
            {'name': 'Utility Bill', 'description': 'Utility bill document', 'is_required': True, 'sort_id': 3},
        ]

        for item in defaults:
            employee_document, _ = EmployeeDocument.objects.get_or_create(
                company_id=company_id,
                user=user,
                name=item['name'],
                defaults={
                    'description': item['description'],
                    'sort_id': item['sort_id'],
                    'is_required': item['is_required'],
                },
            )

            if not DocumentRecord.objects.filter(employee_document=employee_document).exists():
                DocumentRecord.objects.create(
                    employee_document=employee_document,
                    status=DocumentRecord.Status.REQUESTED,
                )
