import { describe, it, expect, beforeEach } from 'vitest';
import type Database from 'better-sqlite3';
import { createDb } from '../src/lib/db';
import {
  createPost, updatePost, deletePost, getPostById, getPublishedBySlug,
  listPublished, listAllPosts, listRecent, listArchiveMonths, listByAuthor, type PostInput,
} from '../src/lib/posts';
import { createUser, getUsernameById, listUsers } from '../src/lib/auth';

let db: Database.Database;
beforeEach(() => { db = createDb(':memory:'); });

const base: PostInput = {
  title: 'Titolo', slug: 'titolo', category: 'Contenuti educativi',
  excerpt: 'estratto', body_html: '<p>corpo</p>', cover: null, draft: false,
};

describe('posts repository', () => {
  it('crea e rilegge un post pubblicato', () => {
    const id = createPost(db, base);
    const post = getPostById(db, id)!;
    expect(post.title).toBe('Titolo');
    expect(post.draft).toBe(0);
    expect(post.published_at).not.toBeNull();
  });

  it('bozza non ha published_at e non appare nelle liste pubbliche', () => {
    const id = createPost(db, { ...base, slug: 'bozza', draft: true });
    expect(getPostById(db, id)!.published_at).toBeNull();
    expect(getPublishedBySlug(db, 'bozza')).toBeUndefined();
    expect(listPublished(db).total).toBe(0);
    expect(listAllPosts(db)).toHaveLength(1);
  });

  it('slug duplicato lancia', () => {
    createPost(db, base);
    expect(() => createPost(db, base)).toThrow();
  });

  it('update imposta published_at alla prima pubblicazione e lo conserva', () => {
    const id = createPost(db, { ...base, draft: true });
    updatePost(db, id, { ...base, draft: false });
    const first = getPostById(db, id)!.published_at;
    expect(first).not.toBeNull();
    updatePost(db, id, { ...base, title: 'Nuovo', draft: false });
    expect(getPostById(db, id)!.published_at).toBe(first);
    expect(getPostById(db, id)!.title).toBe('Nuovo');
  });

  it('listPublished filtra per categoria e pagina', () => {
    for (let i = 0; i < 12; i++) {
      createPost(db, { ...base, slug: `post-${i}`, category: i % 2 ? 'Contenuti educativi' : 'Eventi & Presidi' });
    }
    const all = listPublished(db, { page: 1, perPage: 9 });
    expect(all.total).toBe(12);
    expect(all.items).toHaveLength(9);
    const edu = listPublished(db, { category: 'Contenuti educativi' });
    expect(edu.total).toBe(6);
  });

  it('delete rimuove', () => {
    const id = createPost(db, base);
    deletePost(db, id);
    expect(getPostById(db, id)).toBeUndefined();
  });

  it('listRecent e archivio mesi', () => {
    createPost(db, base);
    expect(listRecent(db, 4)).toHaveLength(1);
    const months = listArchiveMonths(db);
    expect(months).toHaveLength(1);
    expect(months[0].count).toBe(1);
    expect(months[0].month).toMatch(/^\d{4}-\d{2}$/);
  });
});

describe('autore articoli', () => {
  it('createPost salva author_id e listByAuthor filtra', () => {
    const aliceId = createUser(db, 'alice', 'segreta123', 'user');
    const bobId = createUser(db, 'bob', 'segreta123', 'user');
    createPost(db, { ...base, slug: 'a1', author_id: aliceId });
    createPost(db, { ...base, slug: 'a2', author_id: aliceId });
    createPost(db, { ...base, slug: 'b1', author_id: bobId });
    expect(listByAuthor(db, aliceId).length).toBe(2);
    expect(listByAuthor(db, bobId).length).toBe(1);
  });

  it('post senza author_id ha author_id null', () => {
    const id = createPost(db, { ...base, slug: 'orfano' });
    expect(getPostById(db, id)!.author_id).toBeNull();
  });

  it('getUsernameById e listUsers', () => {
    const id = createUser(db, 'carla', 'segreta123', 'superuser');
    expect(getUsernameById(db, id)).toBe('carla');
    expect(getUsernameById(db, 99999)).toBeNull();
    expect(listUsers(db).some((u) => u.username === 'carla' && u.role === 'superuser')).toBe(true);
  });
});
