import { describe, expect, it } from 'vitest';

import type { UserProfileScoring } from '@/src/storage/appStorage';

import { advanceSuixinState, buildInitialSuixinState, computeSuixinSolidColor, pickSuixinBaseThemeId } from '../index';
import { computeTFromStep } from '../progress';
import { lerpHex } from '../colorMath';

function buildProfile(partial?: Partial<UserProfileScoring>): UserProfileScoring {
  const base: UserProfileScoring = {
    profile_version: 'v1.2',
    profile_source: 'questionnaire',
    profile_generated_at: '2026-01-30T00:00:00Z',
    profile_confidence: 1.0,
    profile_answered: { stage: true, emotion: true, context: true, need: true },
    stage: { expecting: 1, parenting: 0, unknown: 0 },
    emotion_score: 0.6,
    context: {},
    need: {},
    rule_hits: [],
    hard_rules: { forbidden_risk_flags: [], forbidden_content_predicates: [] },
  };
  return { ...base, ...(partial ?? {}) };
}

describe('suixinTheme', () => {
  it('pickSuixinBaseThemeId: stage.unknown=1 → neutral', () => {
    const p = buildProfile({ stage: { unknown: 1 } as any, need: { rest_balance: 1 } });
    expect(pickSuixinBaseThemeId(p)).toBe('neutral');
  });

  it('pickSuixinBaseThemeId: need 为空 → neutral', () => {
    const p = buildProfile({ need: {} });
    expect(pickSuixinBaseThemeId(p)).toBe('neutral');
  });

  it('pickSuixinBaseThemeId: need 命中 → 对应 base theme', () => {
    const p = buildProfile({ need: { rest_balance: 1 } });
    expect(pickSuixinBaseThemeId(p)).toBe('rest_balance');
  });

  it('computeTFromStep: 始终在 [0,1] 且往返不突跳', () => {
    const ts = Array.from({ length: 80 }).map((_, i) => computeTFromStep({ stepIndex: i, segments: 12, seed: 'boot' }));
    for (const t of ts) {
      expect(t).toBeGreaterThanOrEqual(0);
      expect(t).toBeLessThanOrEqual(1);
    }
    // 往返波形：起点与一个周期后的 t 相同
    expect(computeTFromStep({ stepIndex: 0, segments: 12, seed: 'boot' })).toBe(
      computeTFromStep({ stepIndex: 22, segments: 12, seed: 'boot' }) // 2*(N-1)=22
    );
  });

  it('lerpHex: t=0/1 输出边界色', () => {
    expect(lerpHex('#000000', '#FFFFFF', 0)).toBe('#000000');
    expect(lerpHex('#000000', '#FFFFFF', 1)).toBe('#FFFFFF');
  });

  it('buildInitialSuixinState: 生成可用状态并可推进', () => {
    const p = buildProfile({ need: { emotional_support: 1 } });
    const init = buildInitialSuixinState({ bootId: 'boot-1', profile: p, now: new Date('2026-02-05T00:00:00Z') });
    expect(init.schema_version).toBe(1);
    expect(init.base_theme_id).toBe('emotional_support');
    expect(init.boot_id).toBe('boot-1');
    expect(init.last_color).toMatch(/^#[0-9A-F]{6}$/);

    const next = advanceSuixinState(init, new Date('2026-02-05T00:00:01Z'));
    expect(next.step_index).toBe(1);
    expect(next.base_theme_id).toBe(init.base_theme_id);
    expect(next.last_color).toMatch(/^#[0-9A-F]{6}$/);
  });

  it('computeSuixinSolidColor: 输出为合法 hex', () => {
    const c = computeSuixinSolidColor({ baseThemeId: 'neutral', stepIndex: 3, seed: 'boot' });
    expect(c).toMatch(/^#[0-9A-F]{6}$/);
  });
});

