from rest_framework import serializers

from apps.meetings.models import Meeting
from apps.projects.models import (
    Deliverable,
    FundDocument,
    FundReport,
    IndicatorRecord,
    Project,
    ProjectFund,
    ProjectFundAllocation,
    ProjectFundTranche,
    ProjectIndicator,
    ProjectRisk,
    ProjectSchedule,
    SubmissionVersion,
)
from apps.core.models import Comment, Invitation, User


class DonorSubmissionVersionSerializer(serializers.ModelSerializer):
    file_url = serializers.SerializerMethodField()

    class Meta:
        model = SubmissionVersion
        fields = ["id", "version_number", "file_url", "note", "created_at"]
        read_only_fields = fields

    def get_file_url(self, obj):
        if not obj.file:
            return None
        request = self.context.get("request")
        url = obj.file.url
        return request.build_absolute_uri(url) if request else url


def _versions_for(instance, context):
    from django.contrib.contenttypes.models import ContentType

    versions = SubmissionVersion.objects.filter(
        content_type=ContentType.objects.get_for_model(type(instance)),
        object_id=str(instance.id),
    )
    return DonorSubmissionVersionSerializer(versions, many=True, context=context).data


class DonorProjectSerializer(serializers.ModelSerializer):
    """Curated project view for the donor portal — status/timeline only,
    no team, tasks, or other funders' data."""

    class Meta:
        model = Project
        fields = ["id", "name", "description", "status", "start_date", "end_date"]
        read_only_fields = fields


class DonorFundAllocationSerializer(serializers.ModelSerializer):
    budget_item_code = serializers.CharField(source="budget_item.code", read_only=True)
    budget_item_name = serializers.CharField(source="budget_item.name", read_only=True)

    class Meta:
        model = ProjectFundAllocation
        fields = ["id", "budget_item_code", "budget_item_name", "amount", "note"]
        read_only_fields = fields


class DonorFundTrancheSerializer(serializers.ModelSerializer):
    status_label = serializers.CharField(source="get_status_display", read_only=True)

    class Meta:
        model = ProjectFundTranche
        fields = ["id", "label", "amount", "expected_date", "received_date", "status", "status_label"]
        read_only_fields = fields


class DonorFundReportSerializer(serializers.ModelSerializer):
    kind_label = serializers.CharField(source="get_kind_display", read_only=True)
    status_label = serializers.CharField(source="get_status_display", read_only=True)
    document_url = serializers.SerializerMethodField()
    fund_source = serializers.CharField(source="fund.source", read_only=True)
    project_name = serializers.CharField(source="fund.project.name", read_only=True, default=None)
    versions = serializers.SerializerMethodField()

    class Meta:
        model = FundReport
        fields = [
            "id", "fund", "fund_source", "project_name", "title", "kind", "kind_label",
            "period_start", "period_end", "due_date", "submitted_date",
            "status", "status_label", "document_url",
            "reviewed_at", "review_note", "versions",
        ]
        read_only_fields = fields

    def get_document_url(self, obj):
        if not obj.document:
            return None
        request = self.context.get("request")
        url = obj.document.url
        return request.build_absolute_uri(url) if request else url

    def get_versions(self, obj):
        return _versions_for(obj, self.context)


class DonorFundDocumentSerializer(serializers.ModelSerializer):
    category_label = serializers.CharField(source="get_category_display", read_only=True)
    status_label = serializers.CharField(source="get_status_display", read_only=True)
    document_url = serializers.SerializerMethodField()
    fund_source = serializers.CharField(source="fund.source", read_only=True)
    project_name = serializers.CharField(source="fund.project.name", read_only=True, default=None)

    class Meta:
        model = FundDocument
        fields = [
            "id", "fund", "fund_source", "project_name", "title", "category", "category_label",
            "date", "status", "status_label", "document_url",
        ]
        read_only_fields = fields

    def get_document_url(self, obj):
        if not obj.document:
            return None
        request = self.context.get("request")
        url = obj.document.url
        return request.build_absolute_uri(url) if request else url


class DonorFundSerializer(serializers.ModelSerializer):
    """Read-only fund view for the donor portal, scoped to the requesting
    donor's own funds (see DonorFundViewSet.get_queryset)."""
    status_label = serializers.CharField(source="get_status_display", read_only=True)
    fund_type_label = serializers.CharField(source="get_fund_type_display", read_only=True)
    awardee = serializers.CharField(source="organization.name", read_only=True)
    project = DonorProjectSerializer(read_only=True)

    class Meta:
        model = ProjectFund
        fields = [
            "id", "source", "fund_code", "grant_number", "fund_type", "fund_type_label",
            "awardee", "amount", "currency", "amount_idr", "status", "status_label",
            "agreement_date", "received_date", "project",
        ]
        read_only_fields = fields


class DonorCommentSerializer(serializers.ModelSerializer):
    author_name = serializers.SerializerMethodField()

    class Meta:
        model = Comment
        fields = ["id", "content", "author_name", "created_at"]
        read_only_fields = ["id", "author_name", "created_at"]

    def get_author_name(self, obj):
        return obj.author.get_full_name() or obj.author.username


DELIVERABLE_DONOR_STATUS_LABELS = {
    "in_preparation": "In Preparation",
}


class DonorDeliverableSerializer(serializers.ModelSerializer):
    """Deliverable as the donor sees it: internal workshop statuses are
    collapsed to a single 'in_preparation' stage."""
    type_label = serializers.CharField(source="get_deliverable_type_display", read_only=True)
    fund_source = serializers.CharField(source="fund.source", read_only=True)
    project_name = serializers.CharField(source="fund.project.name", read_only=True, default=None)
    donor_status = serializers.SerializerMethodField()
    donor_status_label = serializers.SerializerMethodField()
    versions = serializers.SerializerMethodField()

    class Meta:
        model = Deliverable
        fields = [
            "id", "fund", "fund_source", "project_name", "title", "deliverable_type",
            "type_label", "description", "acceptance_criteria", "due_date",
            "submitted_date", "approved_date", "donor_status", "donor_status_label",
            "reviewed_at", "review_note", "versions",
        ]
        read_only_fields = fields

    def get_donor_status(self, obj):
        return "in_preparation" if obj.status in Deliverable.INTERNAL_STATUSES else obj.status

    def get_donor_status_label(self, obj):
        status = self.get_donor_status(obj)
        return DELIVERABLE_DONOR_STATUS_LABELS.get(status) or obj.get_status_display()

    def get_versions(self, obj):
        return _versions_for(obj, self.context)


class DonorMilestoneSerializer(serializers.ModelSerializer):
    status_label = serializers.CharField(source="get_status_display", read_only=True)
    project_name = serializers.CharField(source="project.name", read_only=True)

    class Meta:
        model = ProjectSchedule
        fields = [
            "id", "project", "project_name", "title", "description",
            "start_date", "end_date", "revised_end_date", "completed_date",
            "status", "status_label",
        ]
        read_only_fields = fields


class DonorIndicatorRecordSerializer(serializers.ModelSerializer):
    class Meta:
        model = IndicatorRecord
        fields = ["id", "period_date", "value", "note"]
        read_only_fields = fields


class DonorIndicatorSerializer(serializers.ModelSerializer):
    level_label = serializers.CharField(source="get_result_level_display", read_only=True)
    project_name = serializers.CharField(source="project.name", read_only=True)
    current_value = serializers.SerializerMethodField()
    achievement_pct = serializers.SerializerMethodField()
    records = DonorIndicatorRecordSerializer(many=True, read_only=True)

    class Meta:
        model = ProjectIndicator
        fields = [
            "id", "project", "project_name", "code", "name", "description",
            "result_level", "level_label", "unit", "baseline", "target",
            "data_source", "frequency", "current_value", "achievement_pct", "records",
        ]
        read_only_fields = fields

    def get_current_value(self, obj):
        value = obj.current_value()
        return f"{value:.2f}" if value is not None else None

    def get_achievement_pct(self, obj):
        value = obj.current_value()
        if value is None or not obj.target:
            return None
        return round(float(value) / float(obj.target) * 100, 1)


class DonorRiskSerializer(serializers.ModelSerializer):
    """Donor view of a shared risk — mitigation summary included, owner and
    internal notes excluded."""
    status_label = serializers.CharField(source="get_status_display", read_only=True)
    category_label = serializers.CharField(source="get_category_display", read_only=True)
    kind_label = serializers.CharField(source="get_kind_display", read_only=True)
    project_name = serializers.CharField(source="project.name", read_only=True)
    score = serializers.IntegerField(read_only=True)

    class Meta:
        model = ProjectRisk
        fields = [
            "id", "project", "project_name", "kind", "kind_label", "title",
            "category", "category_label", "description", "probability", "impact",
            "score", "mitigation", "status", "status_label", "target_date",
        ]
        read_only_fields = fields


class DonorMeetingSerializer(serializers.ModelSerializer):
    fund_source = serializers.CharField(source="fund.source", read_only=True, default=None)
    project_name = serializers.CharField(source="project.name", read_only=True, default=None)
    status_label = serializers.CharField(source="get_status_display", read_only=True)

    class Meta:
        model = Meeting
        fields = [
            "id", "title", "description", "start_time", "end_time",
            "status", "status_label", "fund", "fund_source", "project_name",
        ]
        read_only_fields = fields


class DonorTeamUserSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ["id", "email", "name", "donor_role", "account_status", "created_at"]
        read_only_fields = fields

    def get_name(self, obj):
        return obj.get_full_name() or obj.email


class DonorTeamInviteSerializer(serializers.Serializer):
    """Donor-admin invite of a teammate into their own company's portal."""
    email = serializers.EmailField()
    donor_role = serializers.ChoiceField(choices=["admin", "viewer"], default="viewer")


class DonorInviteSerializer(serializers.ModelSerializer):
    """Staff-side: invite a donor-portal login for a donor Company, scoped to
    a specific fund's donor (donor_company is set, `role` is not)."""
    link = serializers.SerializerMethodField()

    class Meta:
        model = Invitation
        fields = ["id", "email", "donor_company", "donor_role", "status", "expires_at", "created_at", "link"]
        read_only_fields = ["id", "status", "expires_at", "created_at", "link"]

    def get_link(self, obj):
        from django.conf import settings
        return f"{settings.FRONTEND_URL.rstrip('/')}/invite/accept?token={obj.token}"
