DROP SCHEMA IF EXISTS achievement CASCADE;
CREATE SCHEMA IF NOT EXISTS achievement;

DROP TABLE IF EXISTS achievement.ac_achievement CASCADE;
CREATE TABLE IF NOT EXISTS achievement.ac_achievement (
    achievement_id         VARCHAR(64) PRIMARY KEY,
    achievement_code       VARCHAR(64) UNIQUE NOT NULL,
    achievement_name       VARCHAR(128) NOT NULL,
    achievement_desc       TEXT,
    achievement_category   VARCHAR(32) NOT NULL DEFAULT 'SCORE',
    trigger_event          VARCHAR(32) NOT NULL DEFAULT 'GRADE_PUBLISHED',
    trigger_rule_json      JSONB NOT NULL DEFAULT '{}'::JSONB,
    badge_level            VARCHAR(16) NOT NULL DEFAULT 'BRONZE',
    badge_icon_url         VARCHAR(512),
    status                 VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
    tenant_id              VARCHAR(64) NOT NULL,
    created_by             VARCHAR(64),
    created_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT chk_ac_achievement_category
        CHECK (achievement_category IN ('SCORE', 'PROGRESS', 'TEACHING', 'ENGAGEMENT', 'MANUAL')),
    CONSTRAINT chk_ac_achievement_trigger_event
        CHECK (trigger_event IN ('GRADE_PUBLISHED', 'WRONG_QUESTION_MASTERED', 'TASK_COMPLETED', 'REVIEW_COMPLETED', 'MANUAL')),
    CONSTRAINT chk_ac_achievement_badge_level
        CHECK (badge_level IN ('BRONZE', 'SILVER', 'GOLD', 'PLATINUM')),
    CONSTRAINT chk_ac_achievement_status
        CHECK (status IN ('ACTIVE', 'DISABLED')),
    CONSTRAINT chk_ac_achievement_trigger_rule_json
        CHECK (jsonb_typeof(trigger_rule_json) = 'object'),
    CONSTRAINT fk_ac_achievement_created_by
        FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id)
);
COMMENT ON TABLE achievement.ac_achievement IS '成就定义表';
COMMENT ON COLUMN achievement.ac_achievement.achievement_id IS '成就ID';
COMMENT ON COLUMN achievement.ac_achievement.achievement_code IS '成就编码';
COMMENT ON COLUMN achievement.ac_achievement.achievement_name IS '成就名称';
COMMENT ON COLUMN achievement.ac_achievement.achievement_desc IS '成就描述';
COMMENT ON COLUMN achievement.ac_achievement.achievement_category IS '成就类别（SCORE/PROGRESS/TEACHING/ENGAGEMENT/MANUAL）';
COMMENT ON COLUMN achievement.ac_achievement.trigger_event IS '触发事件（GRADE_PUBLISHED/WRONG_QUESTION_MASTERED/TASK_COMPLETED/REVIEW_COMPLETED/MANUAL）';
COMMENT ON COLUMN achievement.ac_achievement.trigger_rule_json IS '触发规则JSON（可配置成绩阈值、次数阈值等）';
COMMENT ON COLUMN achievement.ac_achievement.badge_level IS '徽章等级（BRONZE/SILVER/GOLD/PLATINUM）';
COMMENT ON COLUMN achievement.ac_achievement.badge_icon_url IS '徽章图标URL';
COMMENT ON COLUMN achievement.ac_achievement.status IS '状态（ACTIVE/DISABLED）';
COMMENT ON COLUMN achievement.ac_achievement.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_achievement.created_by IS '创建人ID';
COMMENT ON COLUMN achievement.ac_achievement.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_achievement.updated_at IS '更新时间';

DROP TABLE IF EXISTS achievement.ac_achievement_role_rel CASCADE;
CREATE TABLE IF NOT EXISTS achievement.ac_achievement_role_rel (
    achievement_id         VARCHAR(64) NOT NULL,
    role_id                VARCHAR(64) NOT NULL,
    tenant_id              VARCHAR(64) NOT NULL,
    created_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (achievement_id, role_id),
    CONSTRAINT fk_ac_achievement_role_rel_achievement
        FOREIGN KEY (achievement_id) REFERENCES achievement.ac_achievement(achievement_id) ON DELETE CASCADE,
    CONSTRAINT fk_ac_achievement_role_rel_role
        FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id)
);
COMMENT ON TABLE achievement.ac_achievement_role_rel IS '成就-角色绑定表';
COMMENT ON COLUMN achievement.ac_achievement_role_rel.achievement_id IS '成就ID';
COMMENT ON COLUMN achievement.ac_achievement_role_rel.role_id IS '角色ID';
COMMENT ON COLUMN achievement.ac_achievement_role_rel.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_achievement_role_rel.created_at IS '创建时间';

DROP TABLE IF EXISTS achievement.ac_user_achievement CASCADE;
CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement (
    user_achievement_id     VARCHAR(64) PRIMARY KEY,
    user_id                 VARCHAR(64) NOT NULL,
    achievement_id          VARCHAR(64) NOT NULL,
    role_id                 VARCHAR(64) NOT NULL,
    summary_id              VARCHAR(64),
    grading_task_id         VARCHAR(64),
    score_snapshot          NUMERIC(8,2),
    grade_level             VARCHAR(8),
    surpass_ratio           NUMERIC(5,2),
    used_seconds            INTEGER,
    award_source            VARCHAR(32) NOT NULL DEFAULT 'RULE_ENGINE',
    award_reason            VARCHAR(256),
    evidence_json           JSONB NOT NULL DEFAULT '{}'::JSONB,
    achieved_count          INTEGER NOT NULL DEFAULT 1,
    first_achieved_at       TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    last_achieved_at        TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    tenant_id               VARCHAR(64) NOT NULL,
    created_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_ac_user_achievement_user_achievement_role
        UNIQUE (user_id, achievement_id, role_id),
    CONSTRAINT chk_ac_user_achievement_award_source
        CHECK (award_source IN ('RULE_ENGINE', 'MANUAL', 'SYSTEM')),
    CONSTRAINT chk_ac_user_achievement_evidence_json
        CHECK (jsonb_typeof(evidence_json) = 'object'),
    CONSTRAINT chk_ac_user_achievement_achieved_count
        CHECK (achieved_count > 0),
    CONSTRAINT fk_ac_user_achievement_user
        FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
    CONSTRAINT fk_ac_user_achievement_role_binding
        FOREIGN KEY (achievement_id, role_id) REFERENCES achievement.ac_achievement_role_rel(achievement_id, role_id),
    CONSTRAINT fk_ac_user_achievement_summary
        FOREIGN KEY (summary_id) REFERENCES question.gd_score_summary(summary_id),
    CONSTRAINT fk_ac_user_achievement_task
        FOREIGN KEY (grading_task_id) REFERENCES question.gd_grading_task(grading_task_id)
);
COMMENT ON TABLE achievement.ac_user_achievement IS '用户成就记录表';
COMMENT ON COLUMN achievement.ac_user_achievement.user_achievement_id IS '用户成就记录ID';
COMMENT ON COLUMN achievement.ac_user_achievement.user_id IS '用户ID';
COMMENT ON COLUMN achievement.ac_user_achievement.achievement_id IS '成就ID';
COMMENT ON COLUMN achievement.ac_user_achievement.role_id IS '获奖时角色ID';
COMMENT ON COLUMN achievement.ac_user_achievement.summary_id IS '成绩汇总ID（来源于question.gd_score_summary）';
COMMENT ON COLUMN achievement.ac_user_achievement.grading_task_id IS '批改任务ID（来源于question.gd_grading_task）';
COMMENT ON COLUMN achievement.ac_user_achievement.score_snapshot IS '成绩快照分数';
COMMENT ON COLUMN achievement.ac_user_achievement.grade_level IS '成绩快照等级';
COMMENT ON COLUMN achievement.ac_user_achievement.surpass_ratio IS '成绩快照超越比例';
COMMENT ON COLUMN achievement.ac_user_achievement.used_seconds IS '成绩快照耗时（秒）';
COMMENT ON COLUMN achievement.ac_user_achievement.award_source IS '发放来源（RULE_ENGINE/MANUAL/SYSTEM）';
COMMENT ON COLUMN achievement.ac_user_achievement.award_reason IS '发放原因';
COMMENT ON COLUMN achievement.ac_user_achievement.evidence_json IS '发放证据JSON（可存规则命中明细）';
COMMENT ON COLUMN achievement.ac_user_achievement.achieved_count IS '累计达成次数';
COMMENT ON COLUMN achievement.ac_user_achievement.first_achieved_at IS '首次达成时间';
COMMENT ON COLUMN achievement.ac_user_achievement.last_achieved_at IS '最近达成时间';
COMMENT ON COLUMN achievement.ac_user_achievement.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_user_achievement.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_user_achievement.updated_at IS '更新时间';
DROP TABLE IF EXISTS achievement.ac_user_achievement_progress CASCADE;
CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement_progress (
    progress_id             VARCHAR(64) PRIMARY KEY,
    user_id                 VARCHAR(64) NOT NULL,
    achievement_id          VARCHAR(64) NOT NULL,
    role_id                 VARCHAR(64) NOT NULL,
    current_value           NUMERIC(12,2) NOT NULL DEFAULT 0,
    target_value            NUMERIC(12,2) NOT NULL,
    progress_rate           NUMERIC(5,2) NOT NULL DEFAULT 0,
    effort_index            NUMERIC(6,2) NOT NULL DEFAULT 0,
    improvement_rate        NUMERIC(6,2) NOT NULL DEFAULT 0,
    resilience_index        NUMERIC(6,2) NOT NULL DEFAULT 0,
    streak_days             INTEGER NOT NULL DEFAULT 0,
    last_checkin_date       DATE,
    progress_status         VARCHAR(16) NOT NULL DEFAULT 'IN_PROGRESS',
    progress_snapshot_json  JSONB NOT NULL DEFAULT '{}'::JSONB,
    last_evaluated_at       TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    achieved_at             TIMESTAMP,
    tenant_id               VARCHAR(64) NOT NULL,
    created_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_ac_user_achievement_progress_user_achievement_role
        UNIQUE (user_id, achievement_id, role_id),
    CONSTRAINT chk_ac_user_achievement_progress_current
        CHECK (current_value >= 0),
    CONSTRAINT chk_ac_user_achievement_progress_target
        CHECK (target_value > 0),
    CONSTRAINT chk_ac_user_achievement_progress_rate
        CHECK (progress_rate >= 0 AND progress_rate <= 100),
    CONSTRAINT chk_ac_user_achievement_progress_effort_index
        CHECK (effort_index >= 0 AND effort_index <= 100),
    CONSTRAINT chk_ac_user_achievement_progress_improvement_rate
        CHECK (improvement_rate >= -100 AND improvement_rate <= 1000),
    CONSTRAINT chk_ac_user_achievement_progress_resilience_index
        CHECK (resilience_index >= 0 AND resilience_index <= 100),
    CONSTRAINT chk_ac_user_achievement_progress_streak_days
        CHECK (streak_days >= 0),
    CONSTRAINT chk_ac_user_achievement_progress_status
        CHECK (progress_status IN ('IN_PROGRESS', 'ACHIEVED', 'EXPIRED')),
    CONSTRAINT chk_ac_user_achievement_progress_snapshot_json
        CHECK (jsonb_typeof(progress_snapshot_json) = 'object'),
    CONSTRAINT chk_ac_user_achievement_progress_achieved_at
        CHECK (
            (progress_status = 'ACHIEVED' AND achieved_at IS NOT NULL)
            OR (progress_status IN ('IN_PROGRESS', 'EXPIRED') AND achieved_at IS NULL)
        ),
    CONSTRAINT fk_ac_user_achievement_progress_user
        FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
    CONSTRAINT fk_ac_user_achievement_progress_role_binding
        FOREIGN KEY (achievement_id, role_id) REFERENCES achievement.ac_achievement_role_rel(achievement_id, role_id)
);
COMMENT ON TABLE achievement.ac_user_achievement_progress IS '用户成就进度表（含未达成记录）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_id IS '成就进度ID';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.user_id IS '用户ID';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.achievement_id IS '成就ID';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.role_id IS '角色ID（学生/教师）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.current_value IS '当前进度值';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.target_value IS '目标值';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_rate IS '完成率（0-100）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.effort_index IS '努力指数（0-100）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.improvement_rate IS '进步率（可为负）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.resilience_index IS '学习韧性指数（0-100）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.streak_days IS '连续打卡天数';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.last_checkin_date IS '最近打卡日期';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_status IS '进度状态（IN_PROGRESS/ACHIEVED/EXPIRED）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_snapshot_json IS '进度快照JSON（可记录最近一次评估明细）';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.last_evaluated_at IS '最近评估时间';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.achieved_at IS '达成时间';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_user_achievement_progress.updated_at IS '更新时间';

DROP TABLE IF EXISTS achievement.ac_user_achievement_daily_fact CASCADE;
CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement_daily_fact (
    stat_date                 DATE NOT NULL,
    user_id                   VARCHAR(64) NOT NULL,
    role_id                   VARCHAR(64) NOT NULL,
    tenant_id                 VARCHAR(64) NOT NULL,
    gained_achievement_count  INTEGER NOT NULL DEFAULT 0,
    active_achievement_count  INTEGER NOT NULL DEFAULT 0,
    progress_delta            NUMERIC(10,4) NOT NULL DEFAULT 0,
    effort_index              NUMERIC(6,2) NOT NULL DEFAULT 0,
    improvement_rate          NUMERIC(6,2) NOT NULL DEFAULT 0,
    resilience_index          NUMERIC(6,2) NOT NULL DEFAULT 0,
    streak_days               INTEGER NOT NULL DEFAULT 0,
    learning_minutes          INTEGER NOT NULL DEFAULT 0,
    checkin_status            VARCHAR(16) NOT NULL DEFAULT 'NONE',
    created_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at                TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (stat_date, user_id, role_id),
    CONSTRAINT chk_ac_user_achievement_daily_fact_gained
        CHECK (gained_achievement_count >= 0),
    CONSTRAINT chk_ac_user_achievement_daily_fact_active
        CHECK (active_achievement_count >= 0),
    CONSTRAINT chk_ac_user_achievement_daily_fact_effort
        CHECK (effort_index >= 0 AND effort_index <= 100),
    CONSTRAINT chk_ac_user_achievement_daily_fact_improvement
        CHECK (improvement_rate >= -100 AND improvement_rate <= 1000),
    CONSTRAINT chk_ac_user_achievement_daily_fact_resilience
        CHECK (resilience_index >= 0 AND resilience_index <= 100),
    CONSTRAINT chk_ac_user_achievement_daily_fact_streak
        CHECK (streak_days >= 0),
    CONSTRAINT chk_ac_user_achievement_daily_fact_learning_minutes
        CHECK (learning_minutes >= 0),
    CONSTRAINT chk_ac_user_achievement_daily_fact_checkin
        CHECK (checkin_status IN ('NONE', 'CHECKED_IN', 'BROKEN')),
    CONSTRAINT fk_ac_user_achievement_daily_fact_user
        FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
    CONSTRAINT fk_ac_user_achievement_daily_fact_role
        FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id)
);
COMMENT ON TABLE achievement.ac_user_achievement_daily_fact IS '用户成就激励日事实表（激励数据即成就数据）';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.stat_date IS '统计日期';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.user_id IS '用户ID';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.role_id IS '角色ID';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.gained_achievement_count IS '当日新增成就数';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.active_achievement_count IS '当日活跃成就数';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.progress_delta IS '当日进度变化量';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.effort_index IS '当日努力指数（0-100）';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.improvement_rate IS '当日进步率（可为负）';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.resilience_index IS '当日学习韧性指数（0-100）';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.streak_days IS '当日连续打卡天数';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.learning_minutes IS '当日学习分钟数';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.checkin_status IS '打卡状态';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.updated_at IS '更新时间';

DROP TABLE IF EXISTS achievement.ac_achievement_rule_template CASCADE;
DROP TABLE IF EXISTS achievement.ac_achievement_metric_def CASCADE;
DROP TABLE IF EXISTS achievement.ac_achievement_event_dict CASCADE;
CREATE TABLE IF NOT EXISTS achievement.ac_achievement_event_dict (
    event_code              VARCHAR(64) PRIMARY KEY,
    event_name              VARCHAR(128) NOT NULL,
    event_domain            VARCHAR(32) NOT NULL DEFAULT 'LEARNING_LOOP',
    event_desc              TEXT,
    payload_schema_json     JSONB NOT NULL DEFAULT '{}'::JSONB,
    enabled                 BOOLEAN NOT NULL DEFAULT TRUE,
    tenant_id               VARCHAR(64) NOT NULL,
    created_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at              TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT chk_ac_achievement_event_dict_domain
        CHECK (event_domain IN ('LEARNING_LOOP', 'GRADING', 'REVIEW', 'CHECKIN', 'SYSTEM')),
    CONSTRAINT chk_ac_achievement_event_dict_payload_json
        CHECK (jsonb_typeof(payload_schema_json) = 'object')
);
COMMENT ON TABLE achievement.ac_achievement_event_dict IS '成就事件字典表（通用触发事件定义）';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_code IS '事件编码';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_name IS '事件名称';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_domain IS '事件域';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_desc IS '事件描述';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.payload_schema_json IS '事件载荷结构定义JSON';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.enabled IS '是否启用';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_achievement_event_dict.updated_at IS '更新时间';

CREATE TABLE IF NOT EXISTS achievement.ac_achievement_metric_def (
    metric_id                VARCHAR(64) PRIMARY KEY,
    metric_code              VARCHAR(64) NOT NULL,
    metric_name              VARCHAR(128) NOT NULL,
    metric_type              VARCHAR(16) NOT NULL DEFAULT 'NUM',
    metric_unit              VARCHAR(32),
    source_domain            VARCHAR(32) NOT NULL DEFAULT 'SYSTEM',
    agg_method               VARCHAR(16) NOT NULL DEFAULT 'LATEST',
    default_value_num        NUMERIC(18,6),
    default_value_text       VARCHAR(255),
    expr_json                JSONB NOT NULL DEFAULT '{}'::JSONB,
    enabled                  BOOLEAN NOT NULL DEFAULT TRUE,
    tenant_id                VARCHAR(64) NOT NULL,
    created_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_ac_achievement_metric_def_tenant_code
        UNIQUE (tenant_id, metric_code),
    CONSTRAINT chk_ac_achievement_metric_def_type
        CHECK (metric_type IN ('NUM', 'BOOL', 'TEXT', 'RATE', 'COUNT')),
    CONSTRAINT chk_ac_achievement_metric_def_source_domain
        CHECK (source_domain IN ('COURSE', 'HOMEWORK', 'GRADING', 'REVIEW', 'RECOMMENDATION', 'ACHIEVEMENT', 'SYSTEM')),
    CONSTRAINT chk_ac_achievement_metric_def_agg_method
        CHECK (agg_method IN ('LATEST', 'SUM', 'AVG', 'MAX', 'MIN', 'COUNT')),
    CONSTRAINT chk_ac_achievement_metric_def_expr_json
        CHECK (jsonb_typeof(expr_json) = 'object')
);
COMMENT ON TABLE achievement.ac_achievement_metric_def IS '成就指标定义表（通用指标注册）';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_id IS '指标ID';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_code IS '指标编码';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_name IS '指标名称';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_type IS '指标类型';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_unit IS '指标单位';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.source_domain IS '指标来源域';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.agg_method IS '聚合方式';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.default_value_num IS '默认数值';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.default_value_text IS '默认文本值';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.expr_json IS '计算表达式JSON';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.enabled IS '是否启用';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_achievement_metric_def.updated_at IS '更新时间';

CREATE TABLE IF NOT EXISTS achievement.ac_achievement_rule_template (
    template_id              VARCHAR(64) PRIMARY KEY,
    template_code            VARCHAR(64) NOT NULL,
    template_name            VARCHAR(128) NOT NULL,
    event_code               VARCHAR(64) NOT NULL,
    role_id                  VARCHAR(64),
    achievement_category     VARCHAR(32) NOT NULL DEFAULT 'PROGRESS',
    rule_condition_json      JSONB NOT NULL DEFAULT '{}'::JSONB,
    reward_action_json       JSONB NOT NULL DEFAULT '{}'::JSONB,
    priority                 INTEGER NOT NULL DEFAULT 100,
    template_status          VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
    valid_from               TIMESTAMP,
    valid_to                 TIMESTAMP,
    tenant_id                VARCHAR(64) NOT NULL,
    created_by               VARCHAR(64),
    created_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_ac_achievement_rule_template_tenant_code
        UNIQUE (tenant_id, template_code),
    CONSTRAINT chk_ac_achievement_rule_template_category
        CHECK (achievement_category IN ('SCORE', 'PROGRESS', 'TEACHING', 'ENGAGEMENT', 'MANUAL')),
    CONSTRAINT chk_ac_achievement_rule_template_status
        CHECK (template_status IN ('ACTIVE', 'INACTIVE', 'ARCHIVED')),
    CONSTRAINT chk_ac_achievement_rule_template_condition_json
        CHECK (jsonb_typeof(rule_condition_json) = 'object'),
    CONSTRAINT chk_ac_achievement_rule_template_reward_json
        CHECK (jsonb_typeof(reward_action_json) = 'object'),
    CONSTRAINT chk_ac_achievement_rule_template_valid
        CHECK (valid_to IS NULL OR valid_from IS NULL OR valid_to >= valid_from),
    CONSTRAINT fk_ac_achievement_rule_template_event
        FOREIGN KEY (event_code) REFERENCES achievement.ac_achievement_event_dict(event_code),
    CONSTRAINT fk_ac_achievement_rule_template_role
        FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id),
    CONSTRAINT fk_ac_achievement_rule_template_created_by
        FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id)
);
COMMENT ON TABLE achievement.ac_achievement_rule_template IS '成就规则模板表（通用配置驱动）';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_id IS '模板ID';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_code IS '模板编码';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_name IS '模板名称';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.event_code IS '触发事件编码';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.role_id IS '适用角色ID';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.achievement_category IS '成就类别';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.rule_condition_json IS '规则条件JSON';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.reward_action_json IS '奖励动作JSON';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.priority IS '优先级';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_status IS '模板状态';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.valid_from IS '生效开始时间';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.valid_to IS '生效结束时间';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.tenant_id IS '租户ID';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.created_by IS '创建人';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.created_at IS '创建时间';
COMMENT ON COLUMN achievement.ac_achievement_rule_template.updated_at IS '更新时间';

CREATE INDEX IF NOT EXISTS idx_ac_achievement_tenant_status
    ON achievement.ac_achievement(tenant_id, status, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ac_achievement_role_rel_role
    ON achievement.ac_achievement_role_rel(role_id, tenant_id);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_user_role
    ON achievement.ac_user_achievement(user_id, role_id, last_achieved_at DESC);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_tenant_time
    ON achievement.ac_user_achievement(tenant_id, last_achieved_at DESC);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_summary
    ON achievement.ac_user_achievement(summary_id);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_task
    ON achievement.ac_user_achievement(grading_task_id);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_user_status
    ON achievement.ac_user_achievement_progress(user_id, role_id, progress_status, last_evaluated_at DESC);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_tenant_status
    ON achievement.ac_user_achievement_progress(tenant_id, progress_status, last_evaluated_at DESC);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_achievement
    ON achievement.ac_user_achievement_progress(achievement_id, role_id);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_streak
    ON achievement.ac_user_achievement_progress(user_id, role_id, streak_days DESC, last_evaluated_at DESC);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_daily_fact_tenant_date
    ON achievement.ac_user_achievement_daily_fact(tenant_id, stat_date DESC);
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_daily_fact_user_date
    ON achievement.ac_user_achievement_daily_fact(user_id, role_id, stat_date DESC);
CREATE INDEX IF NOT EXISTS idx_ac_achievement_event_dict_tenant_enabled
    ON achievement.ac_achievement_event_dict(tenant_id, enabled, event_domain);
CREATE INDEX IF NOT EXISTS idx_ac_achievement_metric_def_tenant_enabled
    ON achievement.ac_achievement_metric_def(tenant_id, enabled, source_domain);
CREATE INDEX IF NOT EXISTS idx_ac_achievement_rule_template_tenant_event
    ON achievement.ac_achievement_rule_template(tenant_id, event_code, template_status, priority);
