"""
PM Entity-Model Mappers.

تبدیل بین Domain Entities و ORM Models.
"""
from typing import Optional

from ..persistence.models import (
    ProjectModel,
    TaskModel,
    DependencyModel,
    ResourceModel,
    ResourceAssignmentModel,
    BudgetModel,
    CostEntryModel,
    RiskModel,
    BaselineModel,
    CalendarModel,
    HolidayModel,
    ChangeRequestModel,
    TimesheetModel,
    ProjectMemberModel,
    CommentModel,
    ActivityLogModel,
    TaskAssignmentModel,
    TaskLabelModel,
    TaskLabelAssignmentModel,
    TaskAttachmentModel,
    TaskChecklistModel,
    TaskChecklistItemModel,
    RACIAssignmentModel,
    ActivityCodeTypeModel,
    ActivityCodeValueModel,
    TaskActivityCodeModel,
    UDFDefinitionModel,
    UDFValueModel,
    ResourceSkillModel,
    ResourceAvailabilityModel,
    ResourceCostRateModel,
    CostAccountModel,
    FundingSourceModel,
    CashFlowEntryModel,
    ScheduleHealthSnapshotModel,
    ProjectTemplateModel,
    IssueModel,
    QualityPlanModel,
    InspectionModel,
    NCRModel,
    QualityChecklistModel,
    QualityChecklistItemModel,
    ProjectDocumentModel,
)
from ...domain.entities.project import Project
from ...domain.entities.task import Task, Dependency, TaskAssignment
from ...domain.entities.resource import Resource, ResourceAssignment
from ...domain.entities.cost import Budget, CostEntry
from ...domain.entities.risk import Risk
from ...domain.entities.supporting import (
    Baseline, Calendar, Holiday, ChangeRequest,
    Timesheet, ProjectMember, Comment, ActivityLog,
)
from ...domain.entities.kanban import (
    TaskLabel, TaskLabelAssignment,
    TaskAttachment, TaskChecklist, TaskChecklistItem,
    RACIAssignment,
)
from ...domain.entities.advanced import (
    ActivityCodeType, ActivityCodeValue, TaskActivityCode,
    UDFDefinition, UDFValue,
    ResourceSkill, ResourceAvailability, ResourceCostRate,
    CostAccount, FundingSource, CashFlowEntry,
    ScheduleHealthSnapshot, ProjectTemplate,
)
from ...domain.entities.issue import Issue
from ...domain.entities.obs import OBSNode
from ...domain.entities.rbs import RBSNode
from ...domain.entities.quality import (
    QualityPlan, Inspection, NCR,
    QualityChecklist, QualityChecklistItem,
)
from ...domain.entities.project_document import ProjectDocument


# ═══════════════════════════════════════════════════
# Project Mapper
# ═══════════════════════════════════════════════════

class ProjectMapper:

    @staticmethod
    def to_entity(model: ProjectModel) -> Project:
        return Project(
            id=model.id,
            tenant_id=model.tenant_id,
            code=model.code,
            title=model.title,
            description=model.description,
            project_type=model.project_type,
            parent_id=model.parent_id,
            status=model.status,
            priority=model.priority,
            planned_start=model.planned_start,
            planned_end=model.planned_end,
            actual_start=model.actual_start,
            actual_end=model.actual_end,
            progress=model.progress,
            total_budget=model.total_budget,
            actual_cost=model.actual_cost,
            estimated_cost=model.estimated_cost,
            company_id=model.company_id,
            org_unit_id=model.org_unit_id,
            currency_id=model.currency_id,
            manager_id=model.manager_id,
            calendar_id=model.calendar_id,
            color=model.color,
            tags=model.tags or [],
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
            created_by=model.created_by_id,
            updated_by=model.updated_by_id,
        )

    @staticmethod
    def to_model(entity: Project, model: Optional[ProjectModel] = None) -> ProjectModel:
        if model is None:
            model = ProjectModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.project_type = entity.project_type
        model.parent_id = entity.parent_id
        model.status = entity.status
        model.priority = entity.priority
        model.planned_start = entity.planned_start
        model.planned_end = entity.planned_end
        model.actual_start = entity.actual_start
        model.actual_end = entity.actual_end
        model.progress = entity.progress
        model.total_budget = entity.total_budget
        model.actual_cost = entity.actual_cost
        model.estimated_cost = entity.estimated_cost
        model.company_id = entity.company_id
        model.org_unit_id = entity.org_unit_id
        model.currency_id = entity.currency_id
        model.manager_id = entity.manager_id
        model.calendar_id = entity.calendar_id
        model.color = entity.color
        model.tags = entity.tags
        model.metadata = entity.metadata
        model.created_by_id = entity.created_by
        model.updated_by_id = entity.updated_by
        return model


# ═══════════════════════════════════════════════════
# Task Mapper
# ═══════════════════════════════════════════════════

class TaskMapper:

    @staticmethod
    def to_entity(model: TaskModel) -> Task:
        return Task(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            code=model.code,
            title=model.title,
            description=model.description,
            parent_id=model.parent_id,
            sort_order=model.sort_order,
            task_type=model.task_type,
            status=model.status,
            planned_start=model.planned_start,
            planned_end=model.planned_end,
            actual_start=model.actual_start,
            actual_end=model.actual_end,
            duration=model.duration,
            remaining_duration=model.remaining_duration,
            progress=model.progress,
            planned_cost=model.planned_cost,
            actual_cost=model.actual_cost,
            is_critical=model.is_critical,
            is_milestone=model.is_milestone,
            early_start=model.early_start,
            early_finish=model.early_finish,
            late_start=model.late_start,
            late_finish=model.late_finish,
            total_float=model.total_float,
            free_float=model.free_float,
            assignee_id=model.assignee_id,
            color=model.color,
            tags=model.tags or [],
            notes=model.notes,
            metadata=model.metadata or {},
            # Phase B fields
            percent_complete_type=model.percent_complete_type or "physical",
            constraint_type=model.constraint_type or "asap",
            constraint_date=model.constraint_date,
            deadline=model.deadline,
            scheduling_mode=model.scheduling_mode or "auto",
            duration_type=model.duration_type or "fixed_duration",
            calendar_id=model.calendar_id,
            assignment_policy=model.assignment_policy or "manual",
            is_effort_driven=model.is_effort_driven,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Task, model: Optional[TaskModel] = None) -> TaskModel:
        if model is None:
            model = TaskModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.parent_id = entity.parent_id
        model.sort_order = entity.sort_order
        model.task_type = entity.task_type
        model.status = entity.status
        model.planned_start = entity.planned_start
        model.planned_end = entity.planned_end
        model.actual_start = entity.actual_start
        model.actual_end = entity.actual_end
        model.duration = entity.duration
        model.progress = entity.progress
        model.planned_cost = entity.planned_cost
        model.actual_cost = entity.actual_cost
        model.is_critical = entity.is_critical
        model.is_milestone = entity.is_milestone
        model.early_start = entity.early_start
        model.early_finish = entity.early_finish
        model.late_start = entity.late_start
        model.late_finish = entity.late_finish
        model.total_float = entity.total_float
        model.free_float = entity.free_float
        model.assignee_id = entity.assignee_id
        model.color = entity.color
        model.tags = entity.tags
        model.notes = entity.notes
        model.metadata = entity.metadata
        # Phase B fields
        model.remaining_duration = entity.remaining_duration
        model.percent_complete_type = entity.percent_complete_type
        model.constraint_type = entity.constraint_type
        model.constraint_date = entity.constraint_date
        model.deadline = entity.deadline
        model.scheduling_mode = entity.scheduling_mode
        model.duration_type = entity.duration_type
        model.calendar_id = entity.calendar_id
        model.assignment_policy = entity.assignment_policy
        model.is_effort_driven = entity.is_effort_driven
        return model


# ═══════════════════════════════════════════════════
# Dependency Mapper
# ═══════════════════════════════════════════════════

class DependencyMapper:

    @staticmethod
    def to_entity(model: DependencyModel) -> Dependency:
        return Dependency(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            predecessor_id=model.predecessor_id,
            successor_id=model.successor_id,
            dependency_type=model.dependency_type,
            lag_days=model.lag_days,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: Dependency, model: Optional[DependencyModel] = None) -> DependencyModel:
        if model is None:
            model = DependencyModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.predecessor_id = entity.predecessor_id
        model.successor_id = entity.successor_id
        model.dependency_type = entity.dependency_type
        model.lag_days = entity.lag_days
        return model


# ═══════════════════════════════════════════════════
# Resource Mapper
# ═══════════════════════════════════════════════════

class ResourceMapper:

    @staticmethod
    def to_entity(model: ResourceModel) -> Resource:
        return Resource(
            id=model.id,
            tenant_id=model.tenant_id,
            name=model.name,
            code=model.code,
            resource_type=model.resource_type,
            employee_id=model.employee_id,
            user_id=model.user_id,
            company_id=model.company_id,
            standard_rate=model.standard_rate,
            overtime_rate=model.overtime_rate,
            cost_per_use=model.cost_per_use,
            currency_id=model.currency_id,
            max_units=model.max_units,
            calendar_id=model.calendar_id,
            email=model.email,
            phone=model.phone,
            is_active=model.is_active,
            notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Resource, model: Optional[ResourceModel] = None) -> ResourceModel:
        if model is None:
            model = ResourceModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.name = entity.name
        model.code = entity.code
        model.resource_type = entity.resource_type
        model.employee_id = entity.employee_id
        model.user_id = entity.user_id
        model.company_id = entity.company_id
        model.standard_rate = entity.standard_rate
        model.overtime_rate = entity.overtime_rate
        model.cost_per_use = entity.cost_per_use
        model.currency_id = entity.currency_id
        model.max_units = entity.max_units
        model.calendar_id = entity.calendar_id
        model.email = entity.email
        model.phone = entity.phone
        model.is_active = entity.is_active
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# Resource Assignment Mapper
# ═══════════════════════════════════════════════════

class ResourceAssignmentMapper:

    @staticmethod
    def to_entity(model: ResourceAssignmentModel) -> ResourceAssignment:
        return ResourceAssignment(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            resource_id=model.resource_id,
            units=model.units,
            planned_hours=model.planned_hours,
            actual_hours=model.actual_hours,
            planned_cost=model.planned_cost,
            actual_cost=model.actual_cost,
            start_date=model.start_date,
            end_date=model.end_date,
            is_active=model.is_active,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ResourceAssignment, model: Optional[ResourceAssignmentModel] = None) -> ResourceAssignmentModel:
        if model is None:
            model = ResourceAssignmentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.resource_id = entity.resource_id
        model.units = entity.units
        model.planned_hours = entity.planned_hours
        model.actual_hours = entity.actual_hours
        model.planned_cost = entity.planned_cost
        model.actual_cost = entity.actual_cost
        model.start_date = entity.start_date
        model.end_date = entity.end_date
        model.is_active = entity.is_active
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Budget Mapper
# ═══════════════════════════════════════════════════

class BudgetMapper:

    @staticmethod
    def to_entity(model: BudgetModel) -> Budget:
        return Budget(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            name=model.name,
            description=model.description,
            original_budget=model.original_budget,
            revised_budget=model.revised_budget,
            committed_cost=model.committed_cost,
            actual_cost=model.actual_cost,
            currency_id=model.currency_id,
            period_start=model.period_start,
            period_end=model.period_end,
            is_active=model.is_active,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Budget, model: Optional[BudgetModel] = None) -> BudgetModel:
        if model is None:
            model = BudgetModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.name = entity.name
        model.description = entity.description
        model.original_budget = entity.original_budget
        model.revised_budget = entity.revised_budget
        model.committed_cost = entity.committed_cost
        model.actual_cost = entity.actual_cost
        model.currency_id = entity.currency_id
        model.period_start = entity.period_start
        model.period_end = entity.period_end
        model.is_active = entity.is_active
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Cost Entry Mapper
# ═══════════════════════════════════════════════════

class CostEntryMapper:

    @staticmethod
    def to_entity(model: CostEntryModel) -> CostEntry:
        return CostEntry(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            resource_id=model.resource_id,
            budget_id=model.budget_id,
            description=model.description,
            amount=model.amount,
            cost_type=model.cost_type,
            currency_id=model.currency_id,
            entry_date=model.entry_date,
            reference_number=model.reference_number,
            notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at,
            created_by=model.created_by_id,
        )

    @staticmethod
    def to_model(entity: CostEntry, model: Optional[CostEntryModel] = None) -> CostEntryModel:
        if model is None:
            model = CostEntryModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.resource_id = entity.resource_id
        model.budget_id = entity.budget_id
        model.description = entity.description
        model.amount = entity.amount
        model.cost_type = entity.cost_type
        model.currency_id = entity.currency_id
        model.entry_date = entity.entry_date
        model.reference_number = entity.reference_number
        model.notes = entity.notes
        model.metadata = entity.metadata
        model.created_by_id = entity.created_by
        return model


# ═══════════════════════════════════════════════════
# Risk Mapper
# ═══════════════════════════════════════════════════

class RiskMapper:

    @staticmethod
    def to_entity(model: RiskModel) -> Risk:
        return Risk(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            code=model.code,
            title=model.title,
            description=model.description,
            category=model.category,
            probability=model.probability,
            impact=model.impact,
            status=model.status,
            response_strategy=model.response_strategy,
            response_plan=model.response_plan,
            mitigation_actions=model.mitigation_actions,
            owner_id=model.owner_id,
            cost_impact=model.cost_impact,
            schedule_impact_days=model.schedule_impact_days,
            affected_tasks=model.affected_tasks or [],
            identified_date=model.identified_date,
            due_date=model.due_date,
            closed_date=model.closed_date,
            notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Risk, model: Optional[RiskModel] = None) -> RiskModel:
        if model is None:
            model = RiskModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.category = entity.category
        model.probability = entity.probability
        model.impact = entity.impact
        model.status = entity.status
        model.response_strategy = entity.response_strategy
        model.response_plan = entity.response_plan
        model.mitigation_actions = entity.mitigation_actions
        model.owner_id = entity.owner_id
        model.cost_impact = entity.cost_impact
        model.schedule_impact_days = entity.schedule_impact_days
        model.affected_tasks = entity.affected_tasks
        model.identified_date = entity.identified_date
        model.due_date = entity.due_date
        model.closed_date = entity.closed_date
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# Baseline Mapper
# ═══════════════════════════════════════════════════

class BaselineMapper:

    @staticmethod
    def to_entity(model: BaselineModel) -> Baseline:
        return Baseline(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            name=model.name,
            description=model.description,
            baseline_type=model.baseline_type,
            is_active=model.is_active,
            snapshot_date=model.snapshot_date,
            snapshot_data=model.snapshot_data or {},
            total_tasks=model.total_tasks,
            total_cost=model.total_cost,
            planned_start=model.planned_start,
            planned_end=model.planned_end,
            created_at=model.created_at,
            created_by=model.created_by_id,
        )

    @staticmethod
    def to_model(entity: Baseline, model: Optional[BaselineModel] = None) -> BaselineModel:
        if model is None:
            model = BaselineModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.name = entity.name
        model.description = entity.description
        model.baseline_type = entity.baseline_type
        model.is_active = entity.is_active
        model.snapshot_date = entity.snapshot_date
        model.snapshot_data = entity.snapshot_data
        model.total_tasks = entity.total_tasks
        model.total_cost = entity.total_cost
        model.planned_start = entity.planned_start
        model.planned_end = entity.planned_end
        model.created_by_id = entity.created_by
        return model


# ═══════════════════════════════════════════════════
# Calendar & Holiday Mappers
# ═══════════════════════════════════════════════════

class CalendarMapper:

    @staticmethod
    def to_entity(model: CalendarModel) -> Calendar:
        return Calendar(
            id=model.id,
            tenant_id=model.tenant_id,
            name=model.name,
            description=model.description,
            is_default=model.is_default,
            work_start=model.work_start,
            work_end=model.work_end,
            hours_per_day=model.hours_per_day,
            working_days=model.working_days or [],
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Calendar, model: Optional[CalendarModel] = None) -> CalendarModel:
        if model is None:
            model = CalendarModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.name = entity.name
        model.description = entity.description
        model.is_default = entity.is_default
        model.work_start = entity.work_start
        model.work_end = entity.work_end
        model.hours_per_day = entity.hours_per_day
        model.working_days = entity.working_days
        model.metadata = entity.metadata
        return model


class HolidayMapper:

    @staticmethod
    def to_entity(model: HolidayModel) -> Holiday:
        return Holiday(
            id=model.id,
            tenant_id=model.tenant_id,
            calendar_id=model.calendar_id,
            name=model.name,
            holiday_date=model.holiday_date,
            is_recurring=model.is_recurring,
            notes=model.notes,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: Holiday, model: Optional[HolidayModel] = None) -> HolidayModel:
        if model is None:
            model = HolidayModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.calendar_id = entity.calendar_id
        model.name = entity.name
        model.holiday_date = entity.holiday_date
        model.is_recurring = entity.is_recurring
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Change Request Mapper
# ═══════════════════════════════════════════════════

class ChangeRequestMapper:

    @staticmethod
    def to_entity(model: ChangeRequestModel) -> ChangeRequest:
        return ChangeRequest(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            code=model.code,
            title=model.title,
            description=model.description,
            justification=model.justification,
            status=model.status,
            priority=model.priority,
            scope_impact=model.scope_impact,
            cost_impact=model.cost_impact,
            schedule_impact_days=model.schedule_impact_days,
            requester_id=model.requester_id,
            reviewer_id=model.reviewer_id,
            workflow_instance_id=model.workflow_instance_id,
            submitted_date=model.submitted_date,
            decision_date=model.decision_date,
            implementation_date=model.implementation_date,
            decision_notes=model.decision_notes,
            notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ChangeRequest, model: Optional[ChangeRequestModel] = None) -> ChangeRequestModel:
        if model is None:
            model = ChangeRequestModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.justification = entity.justification
        model.status = entity.status
        model.priority = entity.priority
        model.scope_impact = entity.scope_impact
        model.cost_impact = entity.cost_impact
        model.schedule_impact_days = entity.schedule_impact_days
        model.requester_id = entity.requester_id
        model.reviewer_id = entity.reviewer_id
        model.workflow_instance_id = entity.workflow_instance_id
        model.submitted_date = entity.submitted_date
        model.decision_date = entity.decision_date
        model.implementation_date = entity.implementation_date
        model.decision_notes = entity.decision_notes
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# Timesheet Mapper
# ═══════════════════════════════════════════════════

class TimesheetMapper:

    @staticmethod
    def to_entity(model: TimesheetModel) -> Timesheet:
        return Timesheet(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            resource_id=model.resource_id,
            user_id=model.user_id,
            work_date=model.work_date,
            regular_hours=model.regular_hours,
            overtime_hours=model.overtime_hours,
            description=model.description,
            status=model.status,
            approved_by_id=model.approved_by_id,
            approved_date=model.approved_date,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Timesheet, model: Optional[TimesheetModel] = None) -> TimesheetModel:
        if model is None:
            model = TimesheetModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.resource_id = entity.resource_id
        model.user_id = entity.user_id
        model.work_date = entity.work_date
        model.regular_hours = entity.regular_hours
        model.overtime_hours = entity.overtime_hours
        model.description = entity.description
        model.status = entity.status
        model.approved_by_id = entity.approved_by_id
        model.approved_date = entity.approved_date
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Project Member Mapper
# ═══════════════════════════════════════════════════

class ProjectMemberMapper:

    @staticmethod
    def to_entity(model: ProjectMemberModel) -> ProjectMember:
        return ProjectMember(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            user_id=model.user_id,
            role=model.role,
            is_active=model.is_active,
            joined_date=model.joined_date,
            left_date=model.left_date,
            notes=model.notes,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: ProjectMember, model: Optional[ProjectMemberModel] = None) -> ProjectMemberModel:
        if model is None:
            model = ProjectMemberModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.user_id = entity.user_id
        model.role = entity.role
        model.is_active = entity.is_active
        model.joined_date = entity.joined_date
        model.left_date = entity.left_date
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Comment Mapper
# ═══════════════════════════════════════════════════

class CommentMapper:

    @staticmethod
    def to_entity(model: CommentModel) -> Comment:
        return Comment(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            user_id=model.user_id,
            content=model.content,
            parent_id=model.parent_id,
            mentions=model.mentions or [],
            is_edited=model.is_edited,
            is_deleted=model.is_deleted,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Comment, model: Optional[CommentModel] = None) -> CommentModel:
        if model is None:
            model = CommentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.user_id = entity.user_id
        model.content = entity.content
        model.parent_id = entity.parent_id
        model.mentions = entity.mentions
        model.is_edited = entity.is_edited
        model.is_deleted = entity.is_deleted
        return model


# ═══════════════════════════════════════════════════
# Activity Log Mapper
# ═══════════════════════════════════════════════════

class ActivityLogMapper:

    @staticmethod
    def to_entity(model: ActivityLogModel) -> ActivityLog:
        return ActivityLog(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            user_id=model.user_id,
            action=model.action,
            entity_type=model.entity_type,
            entity_id=model.entity_id,
            description=model.description,
            changes=model.changes or {},
            ip_address=model.ip_address,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: ActivityLog, model: Optional[ActivityLogModel] = None) -> ActivityLogModel:
        if model is None:
            model = ActivityLogModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.user_id = entity.user_id
        model.action = entity.action
        model.entity_type = entity.entity_type
        model.entity_id = entity.entity_id
        model.description = entity.description
        model.changes = entity.changes
        model.ip_address = entity.ip_address
        return model


# ═══════════════════════════════════════════════════
# Task Assignment Mapper
# ═══════════════════════════════════════════════════

class TaskAssignmentMapper:

    @staticmethod
    def to_entity(model: TaskAssignmentModel) -> TaskAssignment:
        return TaskAssignment(
            id=model.id,
            tenant_id=model.tenant_id,
            task_id=model.task_id,
            user_id=model.user_id,
            role_id=model.role_id,
            assignment_role=model.assignment_role,
            is_active=model.is_active,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: TaskAssignment, model: Optional[TaskAssignmentModel] = None) -> TaskAssignmentModel:
        if model is None:
            model = TaskAssignmentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.task_id = entity.task_id
        model.user_id = entity.user_id
        model.role_id = entity.role_id
        model.assignment_role = entity.assignment_role
        model.is_active = entity.is_active
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Kanban Mappers (Label, Attachment, Checklist, RACI)
# ═══════════════════════════════════════════════════

class TaskLabelMapper:

    @staticmethod
    def to_entity(model: TaskLabelModel) -> TaskLabel:
        return TaskLabel(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            name=model.name,
            color=model.color,
            description=getattr(model, "description", ""),
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: TaskLabel, model: Optional[TaskLabelModel] = None) -> TaskLabelModel:
        if model is None:
            model = TaskLabelModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.name = entity.name
        model.color = entity.color
        model.sort_order = entity.sort_order
        return model


class TaskLabelAssignmentMapper:

    @staticmethod
    def to_entity(model: TaskLabelAssignmentModel) -> TaskLabelAssignment:
        return TaskLabelAssignment(
            id=model.id,
            tenant_id=model.tenant_id,
            task_id=model.task_id,
            label_id=model.label_id,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: TaskLabelAssignment, model: Optional[TaskLabelAssignmentModel] = None) -> TaskLabelAssignmentModel:
        if model is None:
            model = TaskLabelAssignmentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.task_id = entity.task_id
        model.label_id = entity.label_id
        return model


class TaskAttachmentMapper:

    @staticmethod
    def to_entity(model: TaskAttachmentModel) -> TaskAttachment:
        return TaskAttachment(
            id=model.id,
            tenant_id=model.tenant_id,
            task_id=model.task_id,
            file_name=model.file_name,
            file_url=model.file.url if model.file else "",
            file_size=model.file_size,
            mime_type=model.mime_type,
            uploaded_by=model.uploaded_by_id,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: TaskAttachment, model: Optional[TaskAttachmentModel] = None) -> TaskAttachmentModel:
        if model is None:
            model = TaskAttachmentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.task_id = entity.task_id
        model.file_name = entity.file_name
        model.file_size = entity.file_size
        model.mime_type = entity.mime_type
        model.uploaded_by_id = entity.uploaded_by
        return model


class TaskChecklistMapper:

    @staticmethod
    def to_entity(model: TaskChecklistModel) -> TaskChecklist:
        return TaskChecklist(
            id=model.id,
            tenant_id=model.tenant_id,
            task_id=model.task_id,
            title=model.title,
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: TaskChecklist, model: Optional[TaskChecklistModel] = None) -> TaskChecklistModel:
        if model is None:
            model = TaskChecklistModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.task_id = entity.task_id
        model.title = entity.title
        model.sort_order = entity.sort_order
        return model


class TaskChecklistItemMapper:

    @staticmethod
    def to_entity(model: TaskChecklistItemModel) -> TaskChecklistItem:
        return TaskChecklistItem(
            id=model.id,
            tenant_id=model.tenant_id,
            checklist_id=model.checklist_id,
            title=model.title,
            is_checked=model.is_checked,
            assignee_id=model.assignee_id,
            due_date=model.due_date,
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: TaskChecklistItem, model: Optional[TaskChecklistItemModel] = None) -> TaskChecklistItemModel:
        if model is None:
            model = TaskChecklistItemModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.checklist_id = entity.checklist_id
        model.title = entity.title
        model.is_checked = entity.is_checked
        model.assignee_id = entity.assignee_id
        model.due_date = entity.due_date
        model.sort_order = entity.sort_order
        return model


class RACIAssignmentMapper:

    @staticmethod
    def to_entity(model: RACIAssignmentModel) -> RACIAssignment:
        return RACIAssignment(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            task_id=model.task_id,
            user_id=model.user_id,
            resource_id=model.resource_id,
            role=model.role,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: RACIAssignment, model: Optional[RACIAssignmentModel] = None) -> RACIAssignmentModel:
        if model is None:
            model = RACIAssignmentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.task_id = entity.task_id
        model.user_id = entity.user_id
        model.resource_id = entity.resource_id
        model.role = entity.role
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Activity Code Mappers
# ═══════════════════════════════════════════════════

class ActivityCodeTypeMapper:

    @staticmethod
    def to_entity(model: ActivityCodeTypeModel) -> ActivityCodeType:
        return ActivityCodeType(
            id=model.id,
            tenant_id=model.tenant_id,
            name=model.name,
            code=model.code,
            description=model.description,
            scope=model.scope,
            project_id=model.project_id,
            is_active=model.is_active,
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ActivityCodeType, model: Optional[ActivityCodeTypeModel] = None) -> ActivityCodeTypeModel:
        if model is None:
            model = ActivityCodeTypeModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.name = entity.name
        model.code = entity.code
        model.description = entity.description
        model.scope = entity.scope
        model.project_id = entity.project_id
        model.is_active = entity.is_active
        model.sort_order = entity.sort_order
        return model


class ActivityCodeValueMapper:

    @staticmethod
    def to_entity(model: ActivityCodeValueModel) -> ActivityCodeValue:
        return ActivityCodeValue(
            id=model.id,
            tenant_id=model.tenant_id,
            code_type_id=model.code_type_id,
            parent_id=model.parent_id,
            code=model.code,
            name=model.name,
            description=model.description,
            color=model.color,
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ActivityCodeValue, model: Optional[ActivityCodeValueModel] = None) -> ActivityCodeValueModel:
        if model is None:
            model = ActivityCodeValueModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.code_type_id = entity.code_type_id
        model.parent_id = entity.parent_id
        model.code = entity.code
        model.name = entity.name
        model.description = entity.description
        model.color = entity.color
        model.sort_order = entity.sort_order
        return model


class TaskActivityCodeMapper:

    @staticmethod
    def to_entity(model: TaskActivityCodeModel) -> TaskActivityCode:
        return TaskActivityCode(
            id=model.id,
            tenant_id=model.tenant_id,
            task_id=model.task_id,
            code_value_id=model.code_value_id,
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(entity: TaskActivityCode, model: Optional[TaskActivityCodeModel] = None) -> TaskActivityCodeModel:
        if model is None:
            model = TaskActivityCodeModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.task_id = entity.task_id
        model.code_value_id = entity.code_value_id
        return model


# ═══════════════════════════════════════════════════
# UDF Mappers
# ═══════════════════════════════════════════════════

class UDFDefinitionMapper:

    @staticmethod
    def to_entity(model: UDFDefinitionModel) -> UDFDefinition:
        return UDFDefinition(
            id=model.id,
            tenant_id=model.tenant_id,
            name=model.name,
            code=model.code,
            description=model.description,
            field_type=model.field_type,
            entity_type=model.entity_type,
            default_value=model.default_value,
            options=model.options or [],
            is_required=model.is_required,
            is_active=model.is_active,
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: UDFDefinition, model: Optional[UDFDefinitionModel] = None) -> UDFDefinitionModel:
        if model is None:
            model = UDFDefinitionModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.name = entity.name
        model.code = entity.code
        model.description = entity.description
        model.field_type = entity.field_type
        model.entity_type = entity.entity_type
        model.default_value = entity.default_value
        model.options = entity.options
        model.is_required = entity.is_required
        model.is_active = entity.is_active
        model.sort_order = entity.sort_order
        return model


class UDFValueMapper:

    @staticmethod
    def to_entity(model: UDFValueModel) -> UDFValue:
        return UDFValue(
            id=model.id,
            tenant_id=model.tenant_id,
            definition_id=model.definition_id,
            entity_id=model.entity_id,
            entity_type=model.entity_type,
            value_text=model.value_text,
            value_number=model.value_number,
            value_date=model.value_date,
            value_boolean=model.value_boolean,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: UDFValue, model: Optional[UDFValueModel] = None) -> UDFValueModel:
        if model is None:
            model = UDFValueModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.definition_id = entity.definition_id
        model.entity_id = entity.entity_id
        model.entity_type = entity.entity_type
        model.value_text = entity.value_text
        model.value_number = entity.value_number
        model.value_date = entity.value_date
        model.value_boolean = entity.value_boolean
        return model


# ═══════════════════════════════════════════════════
# Advanced Resource Mappers
# ═══════════════════════════════════════════════════

class ResourceSkillMapper:

    @staticmethod
    def to_entity(model: ResourceSkillModel) -> ResourceSkill:
        return ResourceSkill(
            id=model.id,
            tenant_id=model.tenant_id,
            resource_id=model.resource_id,
            skill_name=model.skill_name,
            proficiency_level=model.proficiency_level,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ResourceSkill, model: Optional[ResourceSkillModel] = None) -> ResourceSkillModel:
        if model is None:
            model = ResourceSkillModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.resource_id = entity.resource_id
        model.skill_name = entity.skill_name
        model.proficiency_level = entity.proficiency_level
        model.notes = entity.notes
        return model


class ResourceAvailabilityMapper:

    @staticmethod
    def to_entity(model: ResourceAvailabilityModel) -> ResourceAvailability:
        return ResourceAvailability(
            id=model.id,
            tenant_id=model.tenant_id,
            resource_id=model.resource_id,
            start_date=model.start_date,
            end_date=model.end_date,
            available_units=model.available_units,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ResourceAvailability, model: Optional[ResourceAvailabilityModel] = None) -> ResourceAvailabilityModel:
        if model is None:
            model = ResourceAvailabilityModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.resource_id = entity.resource_id
        model.start_date = entity.start_date
        model.end_date = entity.end_date
        model.available_units = entity.available_units
        model.notes = entity.notes
        return model


class ResourceCostRateMapper:

    @staticmethod
    def to_entity(model: ResourceCostRateModel) -> ResourceCostRate:
        return ResourceCostRate(
            id=model.id,
            tenant_id=model.tenant_id,
            resource_id=model.resource_id,
            effective_date=model.effective_date,
            standard_rate=model.standard_rate,
            overtime_rate=model.overtime_rate,
            cost_per_use=model.cost_per_use,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ResourceCostRate, model: Optional[ResourceCostRateModel] = None) -> ResourceCostRateModel:
        if model is None:
            model = ResourceCostRateModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.resource_id = entity.resource_id
        model.effective_date = entity.effective_date
        model.standard_rate = entity.standard_rate
        model.overtime_rate = entity.overtime_rate
        model.cost_per_use = entity.cost_per_use
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# CBS & Funding Mappers
# ═══════════════════════════════════════════════════

class CostAccountMapper:

    @staticmethod
    def to_entity(model: CostAccountModel) -> CostAccount:
        return CostAccount(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            parent_id=model.parent_id,
            code=model.code,
            name=model.name,
            description=model.description,
            budget_amount=model.budget_amount,
            actual_amount=model.actual_amount,
            sort_order=model.sort_order,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: CostAccount, model: Optional[CostAccountModel] = None) -> CostAccountModel:
        if model is None:
            model = CostAccountModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.parent_id = entity.parent_id
        model.code = entity.code
        model.name = entity.name
        model.description = entity.description
        model.budget_amount = entity.budget_amount
        model.actual_amount = entity.actual_amount
        model.sort_order = entity.sort_order
        return model


class FundingSourceMapper:

    @staticmethod
    def to_entity(model: FundingSourceModel) -> FundingSource:
        return FundingSource(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            name=model.name,
            description=model.description,
            total_amount=model.total_amount,
            allocated_amount=model.allocated_amount,
            remaining_amount=model.remaining_amount,
            start_date=model.start_date,
            end_date=model.end_date,
            is_active=model.is_active,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: FundingSource, model: Optional[FundingSourceModel] = None) -> FundingSourceModel:
        if model is None:
            model = FundingSourceModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.name = entity.name
        model.description = entity.description
        model.total_amount = entity.total_amount
        model.allocated_amount = entity.allocated_amount
        model.remaining_amount = entity.remaining_amount
        model.start_date = entity.start_date
        model.end_date = entity.end_date
        model.is_active = entity.is_active
        return model


class CashFlowEntryMapper:

    @staticmethod
    def to_entity(model: CashFlowEntryModel) -> CashFlowEntry:
        return CashFlowEntry(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            period_start=model.period_start,
            period_end=model.period_end,
            planned_income=model.planned_income,
            planned_expense=model.planned_expense,
            actual_income=model.actual_income,
            actual_expense=model.actual_expense,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: CashFlowEntry, model: Optional[CashFlowEntryModel] = None) -> CashFlowEntryModel:
        if model is None:
            model = CashFlowEntryModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.period_start = entity.period_start
        model.period_end = entity.period_end
        model.planned_income = entity.planned_income
        model.planned_expense = entity.planned_expense
        model.actual_income = entity.actual_income
        model.actual_expense = entity.actual_expense
        model.notes = entity.notes
        return model


# ═══════════════════════════════════════════════════
# Schedule Health & Template Mappers
# ═══════════════════════════════════════════════════

class ScheduleHealthSnapshotMapper:

    @staticmethod
    def to_entity(model: ScheduleHealthSnapshotModel) -> ScheduleHealthSnapshot:
        return ScheduleHealthSnapshot(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            snapshot_date=model.snapshot_date,
            bei=model.bei,
            cpli=model.cpli,
            spi=model.spi,
            critical_tasks_count=model.critical_tasks_count,
            total_tasks_count=model.total_tasks_count,
            out_of_sequence_count=model.out_of_sequence_count,
            missing_logic_count=model.missing_logic_count,
            negative_float_count=model.negative_float_count,
            high_float_count=model.high_float_count,
            health_score=model.health_score,
            details=model.details or {},
            created_at=model.created_at,
        )

    @staticmethod
    def to_model(
        entity: ScheduleHealthSnapshot,
        model: Optional[ScheduleHealthSnapshotModel] = None,
    ) -> ScheduleHealthSnapshotModel:
        if model is None:
            model = ScheduleHealthSnapshotModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.snapshot_date = entity.snapshot_date
        model.bei = entity.bei
        model.cpli = entity.cpli
        model.spi = entity.spi
        model.critical_tasks_count = entity.critical_tasks_count
        model.total_tasks_count = entity.total_tasks_count
        model.out_of_sequence_count = entity.out_of_sequence_count
        model.missing_logic_count = entity.missing_logic_count
        model.negative_float_count = entity.negative_float_count
        model.high_float_count = entity.high_float_count
        model.health_score = entity.health_score
        model.details = entity.details
        return model


class ProjectTemplateMapper:

    @staticmethod
    def to_entity(model: ProjectTemplateModel) -> ProjectTemplate:
        return ProjectTemplate(
            id=model.id,
            tenant_id=model.tenant_id,
            name=model.name,
            description=model.description,
            category=model.category,
            template_data=model.template_data or {},
            is_active=model.is_active,
            usage_count=model.usage_count,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ProjectTemplate, model: Optional[ProjectTemplateModel] = None) -> ProjectTemplateModel:
        if model is None:
            model = ProjectTemplateModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.name = entity.name
        model.description = entity.description
        model.category = entity.category
        model.template_data = entity.template_data
        model.is_active = entity.is_active
        model.usage_count = entity.usage_count
        return model


# ═══════════════════════════════════════════════════
# Issue Mapper
# ═══════════════════════════════════════════════════

class IssueMapper:

    @staticmethod
    def to_entity(model: IssueModel) -> Issue:
        return Issue(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            code=model.code,
            title=model.title,
            description=model.description,
            category=model.category,
            severity=model.severity,
            priority=model.priority,
            status=model.status,
            reporter_id=model.reporter_id,
            assignee_id=model.assignee_id,
            affected_tasks=model.affected_tasks or [],
            related_risk_id=model.related_risk_id,
            resolution=model.resolution,
            impact_description=model.impact_description,
            cost_impact=model.cost_impact,
            schedule_impact_days=model.schedule_impact_days,
            identified_date=model.identified_date,
            due_date=model.due_date,
            resolved_date=model.resolved_date,
            closed_date=model.closed_date,
            notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Issue, model: Optional[IssueModel] = None) -> IssueModel:
        if model is None:
            model = IssueModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.category = entity.category
        model.severity = entity.severity
        model.priority = entity.priority
        model.status = entity.status
        model.reporter_id = entity.reporter_id
        model.assignee_id = entity.assignee_id
        model.affected_tasks = entity.affected_tasks
        model.related_risk_id = entity.related_risk_id
        model.resolution = entity.resolution
        model.impact_description = entity.impact_description
        model.cost_impact = entity.cost_impact
        model.schedule_impact_days = entity.schedule_impact_days
        model.identified_date = entity.identified_date
        model.due_date = entity.due_date
        model.resolved_date = entity.resolved_date
        model.closed_date = entity.closed_date
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# OBS Node Mapper
# ═══════════════════════════════════════════════════

class OBSNodeMapper:
    @staticmethod
    def to_entity(model: 'OBSNodeModel') -> OBSNode:
        return OBSNode(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            parent_id=model.parent_id,
            code=model.code,
            name=model.name,
            description=model.description,
            node_type=model.node_type,
            level=model.level,
            manager_id=model.manager_id,
            org_unit_id=model.org_unit_id,
            responsibilities=model.responsibilities,
            is_active=model.is_active,
            sort_order=model.sort_order,
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: OBSNode, model: 'OBSNodeModel' = None) -> 'OBSNodeModel':
        from ..persistence.models import OBSNodeModel
        if model is None:
            model = OBSNodeModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.parent_id = entity.parent_id
        model.code = entity.code
        model.name = entity.name
        model.description = entity.description
        model.node_type = entity.node_type
        model.level = entity.level
        model.manager_id = entity.manager_id
        model.org_unit_id = entity.org_unit_id
        model.responsibilities = entity.responsibilities
        model.is_active = entity.is_active
        model.sort_order = entity.sort_order
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# RBS Node Mapper
# ═══════════════════════════════════════════════════

class RBSNodeMapper:
    @staticmethod
    def to_entity(model: 'RBSNodeModel') -> RBSNode:
        return RBSNode(
            id=model.id,
            tenant_id=model.tenant_id,
            project_id=model.project_id,
            parent_id=model.parent_id,
            code=model.code,
            name=model.name,
            description=model.description,
            node_type=model.node_type,
            level=model.level,
            resource_type=model.resource_type,
            unit=model.unit,
            default_rate=float(model.default_rate),
            is_active=model.is_active,
            sort_order=model.sort_order,
            metadata=model.metadata or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: RBSNode, model: 'RBSNodeModel' = None) -> 'RBSNodeModel':
        from ..persistence.models import RBSNodeModel
        if model is None:
            model = RBSNodeModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.parent_id = entity.parent_id
        model.code = entity.code
        model.name = entity.name
        model.description = entity.description
        model.node_type = entity.node_type
        model.level = entity.level
        model.resource_type = entity.resource_type
        model.unit = entity.unit
        model.default_rate = entity.default_rate
        model.is_active = entity.is_active
        model.sort_order = entity.sort_order
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# Quality Plan Mapper
# ═══════════════════════════════════════════════════

class QualityPlanMapper:
    @staticmethod
    def to_entity(model: 'QualityPlanModel') -> QualityPlan:
        return QualityPlan(
            id=model.id, tenant_id=model.tenant_id,
            project_id=model.project_id, name=model.name,
            description=model.description, status=model.status,
            criteria=model.criteria, standards=model.standards,
            objectives=model.objectives, scope=model.scope,
            quality_manager_id=model.quality_manager_id,
            effective_date=model.effective_date,
            review_date=model.review_date,
            version=model.version, notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at, updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: QualityPlan, model: 'QualityPlanModel' = None) -> 'QualityPlanModel':
        from ..persistence.models import QualityPlanModel
        if model is None:
            model = QualityPlanModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.name = entity.name
        model.description = entity.description
        model.status = entity.status
        model.criteria = entity.criteria
        model.standards = entity.standards
        model.objectives = entity.objectives
        model.scope = entity.scope
        model.quality_manager_id = entity.quality_manager_id
        model.effective_date = entity.effective_date
        model.review_date = entity.review_date
        model.version = entity.version
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# Inspection Mapper
# ═══════════════════════════════════════════════════

class InspectionMapper:
    @staticmethod
    def to_entity(model: 'InspectionModel') -> Inspection:
        return Inspection(
            id=model.id, tenant_id=model.tenant_id,
            project_id=model.project_id, code=model.code,
            title=model.title, description=model.description,
            inspection_type=model.inspection_type,
            status=model.status, result=model.result,
            quality_plan_id=model.quality_plan_id,
            task_id=model.task_id, inspector_id=model.inspector_id,
            findings=model.findings, recommendations=model.recommendations,
            planned_date=model.planned_date, actual_date=model.actual_date,
            notes=model.notes, metadata=model.metadata or {},
            created_at=model.created_at, updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: Inspection, model: 'InspectionModel' = None) -> 'InspectionModel':
        from ..persistence.models import InspectionModel
        if model is None:
            model = InspectionModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.inspection_type = entity.inspection_type
        model.status = entity.status
        model.result = entity.result
        model.quality_plan_id = entity.quality_plan_id
        model.task_id = entity.task_id
        model.inspector_id = entity.inspector_id
        model.findings = entity.findings
        model.recommendations = entity.recommendations
        model.planned_date = entity.planned_date
        model.actual_date = entity.actual_date
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# NCR Mapper
# ═══════════════════════════════════════════════════

class NCRMapper:
    @staticmethod
    def to_entity(model: 'NCRModel') -> NCR:
        return NCR(
            id=model.id, tenant_id=model.tenant_id,
            project_id=model.project_id, code=model.code,
            title=model.title, description=model.description,
            severity=model.severity, status=model.status,
            inspection_id=model.inspection_id, task_id=model.task_id,
            reported_by_id=model.reported_by_id,
            assigned_to_id=model.assigned_to_id,
            root_cause=model.root_cause,
            corrective_action=model.corrective_action,
            preventive_action=model.preventive_action,
            cost_impact=model.cost_impact,
            schedule_impact_days=model.schedule_impact_days,
            identified_date=model.identified_date,
            due_date=model.due_date, resolved_date=model.resolved_date,
            closed_date=model.closed_date, notes=model.notes,
            metadata=model.metadata or {},
            created_at=model.created_at, updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: NCR, model: 'NCRModel' = None) -> 'NCRModel':
        from ..persistence.models import NCRModel
        if model is None:
            model = NCRModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.code = entity.code
        model.title = entity.title
        model.description = entity.description
        model.severity = entity.severity
        model.status = entity.status
        model.inspection_id = entity.inspection_id
        model.task_id = entity.task_id
        model.reported_by_id = entity.reported_by_id
        model.assigned_to_id = entity.assigned_to_id
        model.root_cause = entity.root_cause
        model.corrective_action = entity.corrective_action
        model.preventive_action = entity.preventive_action
        model.cost_impact = entity.cost_impact
        model.schedule_impact_days = entity.schedule_impact_days
        model.identified_date = entity.identified_date
        model.due_date = entity.due_date
        model.resolved_date = entity.resolved_date
        model.closed_date = entity.closed_date
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


# ═══════════════════════════════════════════════════
# Quality Checklist Mapper
# ═══════════════════════════════════════════════════

class QualityChecklistMapper:
    @staticmethod
    def to_entity(model: 'QualityChecklistModel') -> QualityChecklist:
        return QualityChecklist(
            id=model.id, tenant_id=model.tenant_id,
            project_id=model.project_id, name=model.name,
            description=model.description,
            quality_plan_id=model.quality_plan_id,
            task_id=model.task_id,
            is_completed=model.is_completed,
            completed_date=model.completed_date,
            completed_by_id=model.completed_by_id,
            notes=model.notes, metadata=model.metadata or {},
            created_at=model.created_at, updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: QualityChecklist, model: 'QualityChecklistModel' = None) -> 'QualityChecklistModel':
        from ..persistence.models import QualityChecklistModel
        if model is None:
            model = QualityChecklistModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.name = entity.name
        model.description = entity.description
        model.quality_plan_id = entity.quality_plan_id
        model.task_id = entity.task_id
        model.is_completed = entity.is_completed
        model.completed_date = entity.completed_date
        model.completed_by_id = entity.completed_by_id
        model.notes = entity.notes
        model.metadata = entity.metadata
        return model


class QualityChecklistItemMapper:
    @staticmethod
    def to_entity(model: 'QualityChecklistItemModel') -> QualityChecklistItem:
        return QualityChecklistItem(
            id=model.id, tenant_id=model.tenant_id,
            checklist_id=model.checklist_id,
            title=model.title, description=model.description,
            sort_order=model.sort_order,
            is_checked=model.is_checked,
            checked_by_id=model.checked_by_id,
            checked_date=model.checked_date,
            result=model.result, remarks=model.remarks,
            created_at=model.created_at, updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: QualityChecklistItem, model: 'QualityChecklistItemModel' = None) -> 'QualityChecklistItemModel':
        from ..persistence.models import QualityChecklistItemModel
        if model is None:
            model = QualityChecklistItemModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.checklist_id = entity.checklist_id
        model.title = entity.title
        model.description = entity.description
        model.sort_order = entity.sort_order
        model.is_checked = entity.is_checked
        model.checked_by_id = entity.checked_by_id
        model.checked_date = entity.checked_date
        model.result = entity.result
        model.remarks = entity.remarks
        return model


class ProjectDocumentMapper:
    @staticmethod
    def to_entity(model: 'ProjectDocumentModel') -> ProjectDocument:
        return ProjectDocument(
            id=model.id, tenant_id=model.tenant_id,
            project_id=model.project_id,
            document_id=model.document_id,
            entity_type=model.entity_type,
            entity_id=model.entity_id,
            title=model.title,
            document_code=model.document_code,
            linked_by=model.linked_by_id,
            notes=model.notes,
            created_at=model.created_at,
            updated_at=model.updated_at,
        )

    @staticmethod
    def to_model(entity: ProjectDocument, model: 'ProjectDocumentModel' = None) -> 'ProjectDocumentModel':
        from ..persistence.models import ProjectDocumentModel
        if model is None:
            model = ProjectDocumentModel(id=entity.id)
        model.tenant_id = entity.tenant_id
        model.project_id = entity.project_id
        model.document_id = entity.document_id
        model.entity_type = entity.entity_type
        model.entity_id = entity.entity_id
        model.title = entity.title
        model.document_code = entity.document_code
        model.linked_by_id = entity.linked_by
        model.notes = entity.notes
        return model
