/*
 * Copyright (c) 2025 SimcuTeam. All rights reserved.
 * 遵循 MIT 许可证。
 */

package simcu::simapi.models

import std.collection.*
import std.reflect.*
import std.time.*
import simcu::simapi.helpers.*

/**
 * 实体基类。
 * 提供：
 *   - Id（默认 Guid）、CreatedAt / UpdatedAt（默认当前时间）
 *   - MapData：反射式字段映射（源 → 目标，同名 + 同类型；可忽略字段/白名单）
 *   - UpdateTime：更新 UpdatedAt
 */
public open class SimApiBaseModel {
    public var _id: String = SimApiUtil.newGuid()
    public var _updatedAt: DateTime = DateTime.now()
    public var _createdAt: DateTime = DateTime.now()

    /// MapData 默认忽略的字段（Id / CreatedAt / UpdatedAt）
    protected var _mapperIgnoreField: Array<String> = ["_id", "_createdAt", "_updatedAt"]

    /// UpdateTime 更新的字段名
    protected var _updatedTimeField: String = "_updatedAt"


    /**
     * 反射映射：把 source 的同名同类型非忽略字段赋值到 this。
     * @param source 源对象。
     * @param mapAll 为 true 时连忽略字段（Id/CreatedAt/UpdatedAt）也映射。
     */
    public func mapData(source: Any, mapAll!: Bool = false): Unit {
        let sourceProps = collectProps(TypeInfo.of(source))
        let targetProps = collectProps(TypeInfo.of(this))
        for (sp in sourceProps) {
            if (mapAll || !_mapperIgnoreField.contains(sp.name)) {
                copyProp(targetProps, sp, source, this)
            }
        }
        updateTime()
    }

    /**
     * 反射映射：仅映射白名单字段。
     * @param source 源对象。
     * @param mapFields 白名单字段名。
     */
    public func mapData(source: Any, mapFields: Array<String>): Unit {
        let sourceProps = collectProps(TypeInfo.of(source))
        let targetProps = collectProps(TypeInfo.of(this))
        for (sp in sourceProps) {
            if (mapFields.contains(sp.name)) {
                copyProp(targetProps, sp, source, this)
            }
        }
        updateTime()
    }

    /**
     * 更新 UpdatedAt 为当前时间。
     */
    public func updateTime(): Unit {
        let targetProps = collectProps(TypeInfo.of(this))
        for (tp in targetProps) {
            if (tp.name == _updatedTimeField) {
                tp.setValue(this, DateTime.now())
                return
            }
        }
    }

    // ===== 内部实现 =====

    /// 把源属性 sp 的值复制到目标对象（要求目标存在同名同类型属性）
    private static func copyProp(targetProps: ArrayList<InstancePropertyInfo>, sp: InstancePropertyInfo,
        source: Any, target: Any): Unit {
        for (tp in targetProps) {
            if (tp.name == sp.name && tp.typeInfo == sp.typeInfo) {
                tp.setValue(target, sp.getValue(source))
                return
            }
        }
    }

    /// 收集类型（含继承链）的 public 实例属性，子类同名覆盖父类
    private static func collectProps(typeInfo: TypeInfo): ArrayList<InstancePropertyInfo> {
        let result = ArrayList<InstancePropertyInfo>()
        collectPropsRecursive(typeInfo, result)
        result
    }

    private static func collectPropsRecursive(typeInfo: TypeInfo, result: ArrayList<InstancePropertyInfo>): Unit {
        if (let ct: ClassTypeInfo <- typeInfo) {
            if (let Some(superType) <- ct.superClass) {
                if (superType != TypeInfo.of<Object>()) {
                    collectPropsRecursive(superType, result)
                }
            }
            for (p in ct.instanceProperties) {
                var replaced = false
                for ((index, existing) in result |> enumerate) {
                    if (existing.name == p.name) {
                        result[index] = p
                        replaced = true
                        break
                    }
                }
                if (!replaced) {
                    result.add(p)
                }
            }
        }
    }
}
