import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import { updatePostTracking, pruneContentHistory, updateFollowerCount } from '../state-updater.mjs';

const SAMPLE_STATE = `---
last_post_date: "2026-04-05"
first_post_date: "2026-01-15"
last_post_topic: "AI strategy"
posts_this_week: 2
weekly_goal: 3
current_streak: 5
longest_streak: 12
current_week: "2026-W14"
last_import_date: "2026-04-01"
last_import_week: "2026-W14"
follower_count: 850
follower_target: 10000
target_date: "2026-12-31"
monthly_growth: []
projected_10k_date: ""
growth_rate_needed: 0
---

# LinkedIn Session State

## Recent Posts

- [2026-04-05] "AI governance is not about..." (1450) - AI strategy
- [2026-04-03] "Three things I learned..." (1200) - leadership
- [2026-03-28] "Why most teams fail at..." (1350) - team building

## Session Notes

## Planned Content

## Milestone Log
`;

describe('updatePostTracking', () => {
  test('sets last_post_date to provided date', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-07',
      postTopic: 'AI governance',
      hookText: 'The real problem with AI governance...',
      charCount: 1500,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^last_post_date: "2026-04-07"$/m);
  });

  test('sets last_post_topic', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-07',
      postTopic: 'AI governance',
      hookText: 'The real problem...',
      charCount: 1500,
      format: 'post'
    });
    assert.match(result.content, /^last_post_topic: "AI governance"$/m);
  });

  test('increments posts_this_week when same week', () => {
    // 2026-04-06 is a Monday, ISO W15. current_week is W14.
    // Use a date that stays in W14: 2026-04-05 is Sunday W14 — but last_post_date is already 04-05.
    // Let's use a state with current_week matching the post date week.
    const w15State = SAMPLE_STATE.replace('current_week: "2026-W14"', 'current_week: "2026-W15"');
    const result = updatePostTracking(w15State, {
      postDate: '2026-04-07', // Tuesday W15
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^posts_this_week: 3$/m); // was 2, incremented
  });

  test('increments streak when gap <= 2 days', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-06', // 1 day after last_post_date 2026-04-05
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^current_streak: 6$/m); // was 5, incremented
  });

  test('resets streak to 1 when gap > 2 days', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-09', // 4 days after 2026-04-05
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^current_streak: 1$/m);
  });

  test('sets first_post_date when null', () => {
    const nullFirstPost = SAMPLE_STATE.replace(
      'first_post_date: "2026-01-15"',
      'first_post_date: null'
    );
    const result = updatePostTracking(nullFirstPost, {
      postDate: '2026-04-07',
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^first_post_date: "2026-04-07"$/m);
  });

  test('does NOT overwrite existing first_post_date', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-07',
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^first_post_date: "2026-01-15"$/m);
  });

  test('triggers week rollover when ISO week changes', () => {
    // 2026-04-14 is W16, current_week is W14
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-14',
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    // After rollover, posts_this_week resets to 0 then increments to 1
    assert.match(result.content, /^posts_this_week: 1$/m);
    assert.match(result.content, /^current_week: "2026-W16"$/m);
  });

  test('appends to Recent Posts section', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-06',
      postTopic: 'AI governance',
      hookText: 'The real problem with AI governance today...',
      charCount: 1500,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.ok(result.content.includes('- [2026-04-06] "The real problem with AI governance today..." (1500) - AI governance'));
    // Existing entries should still be there
    assert.ok(result.content.includes('- [2026-04-05] "AI governance is not about..."'));
  });

  test('updates longest_streak when current exceeds it', () => {
    const highStreak = SAMPLE_STATE.replace('current_streak: 5', 'current_streak: 12');
    const result = updatePostTracking(highStreak, {
      postDate: '2026-04-06', // 1 day gap, streak increments to 13
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^current_streak: 13$/m);
    assert.match(result.content, /^longest_streak: 13$/m);
  });

  test('does not update longest_streak when current is lower', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-06',
      postTopic: 'test',
      hookText: 'Hook',
      charCount: 1000,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^current_streak: 6$/m);
    assert.match(result.content, /^longest_streak: 12$/m); // unchanged
  });

  test('returns changes array describing what changed', () => {
    const result = updatePostTracking(SAMPLE_STATE, {
      postDate: '2026-04-06',
      postTopic: 'AI governance',
      hookText: 'Hook',
      charCount: 1500,
      format: 'post'
    });
    assert.notEqual(result, null);
    assert.ok(Array.isArray(result.changes));
    assert.ok(result.changes.length > 0);
  });
});

describe('pruneContentHistory', () => {
  test('removes entries older than 90 days', () => {
    const today = new Date();
    const old = new Date(today);
    old.setDate(old.getDate() - 100);
    const oldDate = old.toISOString().slice(0, 10);

    const recent = new Date(today);
    recent.setDate(recent.getDate() - 10);
    const recentDate = recent.toISOString().slice(0, 10);

    const stateWithOld = SAMPLE_STATE.replace(
      '## Recent Posts\n\n',
      `## Recent Posts\n\n- [${oldDate}] "Old post..." (1000) - old topic\n- [${recentDate}] "Recent post..." (1200) - recent topic\n`
    );

    const result = pruneContentHistory(stateWithOld, 90);
    assert.notEqual(result, null);
    assert.equal(result.pruned, 1);
    assert.ok(!result.content.includes(oldDate));
    assert.ok(result.content.includes(recentDate));
  });

  test('preserves entries within 90 days', () => {
    const today = new Date();
    const recent = new Date(today);
    recent.setDate(recent.getDate() - 30);
    const recentDate = recent.toISOString().slice(0, 10);

    const stateWithRecent = SAMPLE_STATE.replace(
      '## Recent Posts\n\n',
      `## Recent Posts\n\n- [${recentDate}] "Recent post..." (1200) - topic\n`
    );

    const result = pruneContentHistory(stateWithRecent, 90);
    assert.equal(result, null); // nothing to prune
  });

  test('returns null when no entries exist', () => {
    const emptyRecent = SAMPLE_STATE.replace(
      /## Recent Posts\n\n[\s\S]*?(?=## Session Notes)/,
      '## Recent Posts\n\n'
    );
    const result = pruneContentHistory(emptyRecent, 90);
    assert.equal(result, null);
  });

  test('handles custom maxAgeDays', () => {
    const today = new Date();
    const old = new Date(today);
    old.setDate(old.getDate() - 40);
    const oldDate = old.toISOString().slice(0, 10);

    const stateWithOld = SAMPLE_STATE.replace(
      '## Recent Posts\n\n',
      `## Recent Posts\n\n- [${oldDate}] "Somewhat old..." (1000) - topic\n`
    );

    const result = pruneContentHistory(stateWithOld, 30);
    assert.notEqual(result, null);
    assert.equal(result.pruned, 1);
  });
});

describe('updateFollowerCount', () => {
  test('updates follower_count', () => {
    const result = updateFollowerCount(SAMPLE_STATE, {
      count: 920,
      month: '2026-04'
    });
    assert.notEqual(result, null);
    assert.match(result.content, /^follower_count: 920$/m);
  });

  test('recalculates growth_rate_needed', () => {
    const result = updateFollowerCount(SAMPLE_STATE, {
      count: 920,
      month: '2026-04'
    });
    assert.notEqual(result, null);
    const match = result.content.match(/^growth_rate_needed: (\d+)$/m);
    assert.ok(match, 'growth_rate_needed should be present');
    const rate = parseInt(match[1], 10);
    assert.ok(rate > 0, 'growth_rate_needed should be positive');
  });

  test('appends to Milestone Log section', () => {
    const result = updateFollowerCount(SAMPLE_STATE, {
      count: 920,
      month: '2026-04'
    });
    assert.notEqual(result, null);
    assert.ok(result.content.includes('[2026-04] 920 (+70)'));
  });
});
