from django.contrib.auth import authenticate
from rest_framework import serializers

from accounts.models import User
from blog.models import BlogPost
from companies.models import Company
from jobs.models import Job, JobApplication, JobCategory, SavedJob
from ats.models import ApplicationEvent, ApplicationNote, Interview
from messaging.models import Conversation, Message as ChatMessage
from podcast.models import PodcastEpisode
from seekers.models import SeekerProfile
from subscriptions.models import SubscriptionPlan
from testimonials.models import Testimonial


def absolute_url(serializer, path):
    request = serializer.context.get('request')
    if request:
        return request.build_absolute_uri(path)
    return path


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'username', 'first_name', 'last_name', 'role', 'phone']
        read_only_fields = fields


class JobCategorySerializer(serializers.ModelSerializer):
    numbered_name = serializers.CharField(read_only=True)

    class Meta:
        model = JobCategory
        fields = ['number', 'name', 'numbered_name', 'slug', 'icon', 'sort_order', 'is_active']


class JobListSerializer(serializers.ModelSerializer):
    category = JobCategorySerializer(read_only=True)
    salary_display = serializers.CharField(read_only=True)
    url = serializers.SerializerMethodField()
    job_type_display = serializers.CharField(source='get_job_type_display', read_only=True)
    experience_level_display = serializers.CharField(source='get_experience_level_display', read_only=True)
    experience_display = serializers.CharField(read_only=True)
    logo_url = serializers.CharField(read_only=True)

    class Meta:
        model = Job
        fields = [
            'id', 'slug', 'title', 'company_name', 'company_slug', 'company_initials',
            'company_logo_gradient', 'company_industry', 'location', 'job_type',
            'job_type_display', 'experience_level', 'experience_level_display',
            'experience_required', 'experience_display', 'logo_url',
            'category', 'salary_min', 'salary_max', 'salary_display', 'badge',
            'summary', 'is_featured', 'deadline', 'created_at', 'url',
        ]

    def get_url(self, obj):
        return absolute_url(self, obj.get_absolute_url())


class JobDetailSerializer(JobListSerializer):
    list_items = serializers.DictField(read_only=True)

    class Meta(JobListSerializer.Meta):
        fields = JobListSerializer.Meta.fields + [
            'description', 'list_items', 'how_to_apply', 'cover_image_url',
            'views_count', 'updated_at',
        ]


class JobApplicationSerializer(serializers.ModelSerializer):
    job = JobListSerializer(read_only=True)
    job_slug = serializers.SlugField(write_only=True, required=False)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    applicant_name = serializers.SerializerMethodField()
    applicant_email = serializers.EmailField(source='applicant.email', read_only=True)

    cv_extracted_skills = serializers.SerializerMethodField()
    cv_skill_list = serializers.SerializerMethodField()

    class Meta:
        model = JobApplication
        fields = [
            'id', 'job', 'job_slug', 'cover_letter', 'cv_file', 'linkedin_url',
            'status', 'status_display', 'match_score', 'rating',
            'cv_extracted_skills', 'cv_skill_list', 'cv_parsed_at',
            'applicant_name', 'applicant_email', 'created_at', 'updated_at',
        ]
        read_only_fields = [
            'id', 'job', 'status', 'status_display', 'match_score',
            'cv_extracted_skills', 'cv_skill_list', 'cv_parsed_at',
            'applicant_name', 'applicant_email', 'created_at', 'updated_at',
        ]

    def get_cv_extracted_skills(self, obj):
        return obj.cv_skill_list

    def get_cv_skill_list(self, obj):
        return obj.cv_skill_list

    def get_applicant_name(self, obj):
        return obj.applicant.get_full_name() or obj.applicant.email

    def create(self, validated_data):
        validated_data.pop('job_slug', None)
        validated_data['applicant'] = self.context['request'].user
        validated_data['job'] = self.context['job']
        return super().create(validated_data)


class ApplicationNoteSerializer(serializers.ModelSerializer):
    author_name = serializers.SerializerMethodField()

    class Meta:
        model = ApplicationNote
        fields = ['id', 'body', 'author_name', 'created_at']
        read_only_fields = ['id', 'author_name', 'created_at']

    def get_author_name(self, obj):
        return obj.author.get_full_name() if obj.author else ''


class ApplicationEventSerializer(serializers.ModelSerializer):
    event_type_display = serializers.CharField(source='get_event_type_display', read_only=True)

    class Meta:
        model = ApplicationEvent
        fields = [
            'id', 'event_type', 'event_type_display', 'old_value', 'new_value',
            'message', 'created_at',
        ]


class InterviewSerializer(serializers.ModelSerializer):
    class Meta:
        model = Interview
        fields = [
            'id', 'scheduled_at', 'location', 'meeting_url', 'notes', 'status', 'created_at',
        ]


class EmployerApplicationSerializer(serializers.ModelSerializer):
    job = JobListSerializer(read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    applicant_name = serializers.SerializerMethodField()
    applicant_email = serializers.EmailField(source='applicant.email', read_only=True)
    notes = ApplicationNoteSerializer(many=True, read_only=True)
    events = ApplicationEventSerializer(many=True, read_only=True)
    interviews = InterviewSerializer(many=True, read_only=True)

    class Meta:
        model = JobApplication
        fields = [
            'id', 'job', 'cover_letter', 'cv_file', 'linkedin_url',
            'status', 'status_display', 'match_score', 'rating',
            'applicant_name', 'applicant_email', 'notes', 'events', 'interviews',
            'created_at', 'updated_at',
        ]
        read_only_fields = [
            'id', 'job', 'cover_letter', 'cv_file', 'linkedin_url', 'match_score',
            'applicant_name', 'applicant_email', 'notes', 'events', 'interviews',
            'created_at', 'updated_at',
        ]

    def get_applicant_name(self, obj):
        return obj.applicant.get_full_name() or obj.applicant.email


class ApplicationNoteCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ApplicationNote
        fields = ['body']


class ChatMessageSerializer(serializers.ModelSerializer):
    sender_name = serializers.SerializerMethodField()
    is_mine = serializers.SerializerMethodField()

    class Meta:
        model = ChatMessage
        fields = ['id', 'body', 'sender_name', 'is_mine', 'created_at', 'read_at']
        read_only_fields = ['id', 'sender_name', 'is_mine', 'created_at', 'read_at']

    def get_sender_name(self, obj):
        return obj.sender.get_full_name() or obj.sender.email

    def get_is_mine(self, obj):
        request = self.context.get('request')
        return bool(request and request.user == obj.sender)


class ConversationSerializer(serializers.ModelSerializer):
    job_title = serializers.CharField(source='job.title', read_only=True)
    company_name = serializers.CharField(source='job.company_name', read_only=True)
    application_id = serializers.IntegerField(source='application.id', read_only=True)
    partner_name = serializers.SerializerMethodField()
    unread_count = serializers.IntegerField(read_only=True, required=False)
    last_message = serializers.SerializerMethodField()

    class Meta:
        model = Conversation
        fields = [
            'id', 'application_id', 'job_title', 'company_name', 'partner_name',
            'status', 'closed_at', 'unread_count', 'last_message', 'updated_at', 'created_at',
        ]

    def get_partner_name(self, obj):
        request = self.context.get('request')
        if not request:
            return ''
        other = obj.other_participant(request.user)
        if request.user.is_company:
            profile = getattr(other, 'seeker_profile', None)
            if profile:
                return profile.full_name
        return other.get_full_name() or other.email if other else ''

    def get_last_message(self, obj):
        message = obj.messages.order_by('-created_at').first()
        if not message:
            return None
        return ChatMessageSerializer(message, context=self.context).data


class ChatMessageCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = ChatMessage
        fields = ['body']


class SavedJobSerializer(serializers.ModelSerializer):
    job = JobListSerializer(read_only=True)

    class Meta:
        model = SavedJob
        fields = ['id', 'job', 'created_at']


class CompanySerializer(serializers.ModelSerializer):
    tag_list = serializers.ListField(read_only=True)
    url = serializers.SerializerMethodField()
    tier_display = serializers.CharField(source='get_tier_display', read_only=True)
    open_jobs_count = serializers.SerializerMethodField()

    class Meta:
        model = Company
        fields = [
            'id', 'slug', 'name', 'initials', 'logo_gradient', 'industry',
            'industry_slug', 'location', 'employee_count_display', 'company_size',
            'cover_image_url', 'website', 'description', 'tags', 'tag_list',
            'tier', 'tier_display', 'rating', 'review_count', 'successful_hires',
            'is_featured', 'founded_year', 'open_jobs_count', 'url',
        ]

    def get_url(self, obj):
        return absolute_url(self, obj.get_absolute_url())

    def get_open_jobs_count(self, obj):
        return getattr(obj, 'open_jobs_count', 0)


class SeekerProfileSerializer(serializers.ModelSerializer):
    skill_list = serializers.ListField(read_only=True)
    salary_display = serializers.CharField(read_only=True)
    url = serializers.SerializerMethodField()
    initials = serializers.CharField(read_only=True)
    job_category = JobCategorySerializer(read_only=True)

    class Meta:
        model = SeekerProfile
        fields = [
            'id', 'slug', 'full_name', 'headline', 'job_category', 'category', 'category_slug',
            'location', 'years_experience', 'experience_level', 'availability',
            'tier', 'skills', 'skill_list', 'bio', 'education', 'experience_summary',
            'qualification', 'salary_min', 'salary_max', 'salary_display',
            'is_featured', 'initials', 'url',
        ]

    def get_url(self, obj):
        return absolute_url(self, obj.get_absolute_url())

    def to_representation(self, instance):
        data = super().to_representation(instance)
        request = self.context.get('request')
        if not request:
            return data

        from seekers.profile_access import FULL, resolve_seeker_profile_access

        access = resolve_seeker_profile_access(request, instance, record_view=False)
        if access['level'] == FULL:
            return data

        return {
            'slug': data['slug'],
            'headline': data['headline'],
            'category': data['category'],
            'category_slug': data.get('category_slug'),
            'url': data['url'],
        }


class BlogPostSerializer(serializers.ModelSerializer):
    url = serializers.SerializerMethodField()

    class Meta:
        model = BlogPost
        fields = [
            'id', 'slug', 'title', 'excerpt', 'content', 'category',
            'author_name', 'author_role', 'cover_image_url', 'read_minutes',
            'is_featured', 'published_at', 'url',
        ]

    def get_url(self, obj):
        return absolute_url(self, obj.get_absolute_url())


class PodcastEpisodeSerializer(serializers.ModelSerializer):
    url = serializers.SerializerMethodField()

    class Meta:
        model = PodcastEpisode
        fields = [
            'id', 'slug', 'title', 'description', 'episode_number',
            'duration_display', 'guest_name', 'cover_image_url', 'audio_url',
            'is_featured', 'published_at', 'url',
        ]

    def get_url(self, obj):
        return absolute_url(self, obj.get_absolute_url())


class SubscriptionPlanSerializer(serializers.ModelSerializer):
    feature_list = serializers.ListField(read_only=True)
    audience_display = serializers.CharField(source='get_audience_display', read_only=True)
    category_display = serializers.CharField(source='get_category_display', read_only=True)

    class Meta:
        model = SubscriptionPlan
        fields = [
            'id', 'slug', 'name', 'audience', 'audience_display',
            'category', 'category_display',
            'price_monthly', 'price_label', 'description', 'feature_list',
            'is_featured', 'sort_order',
        ]


class TestimonialSerializer(serializers.ModelSerializer):
    class Meta:
        model = Testimonial
        fields = [
            'id', 'full_name', 'role', 'company', 'story', 'rating',
            'avatar_initials', 'testimonial_type', 'is_featured', 'created_at',
        ]
        read_only_fields = ['id', 'is_featured', 'created_at']


class TestimonialCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Testimonial
        fields = ['full_name', 'role', 'company', 'story', 'rating', 'testimonial_type']

    def create(self, validated_data):
        validated_data['is_approved'] = False
        return super().create(validated_data)


class TokenObtainSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField(write_only=True)

    def validate(self, attrs):
        email = attrs['email'].lower()
        try:
            user = User.objects.get(email__iexact=email)
        except User.DoesNotExist:
            raise serializers.ValidationError('Invalid email or password.')
        user = authenticate(username=user.username, password=attrs['password'])
        if not user:
            raise serializers.ValidationError('Invalid email or password.')
        if not user.is_active:
            raise serializers.ValidationError('This account is inactive.')
        attrs['user'] = user
        return attrs
