import { describe, expect, it } from 'vitest';
import { CmsService } from '../application/cms-service.js';
import { DuplicateSlugError, PageNotFoundError, PageNotPublishedError } from '../domain/errors.js';
import type { CmsRepository } from '../domain/ports.js';
import type { Page } from '../domain/page.js';

const PAGE: Page = {
  id: 'page-1',
  slug: 'about',
  title: 'About',
  body: 'Content',
  status: 'draft',
  createdAt: new Date(),
  updatedAt: new Date(),
};

function repo(overrides: Partial<CmsRepository> = {}): CmsRepository {
  return {
    create: async () => PAGE,
    update: async () => PAGE,
    setStatus: async (id, status) => ({ ...PAGE, id, status }),
    findBySlug: async () => PAGE,
    findById: async () => PAGE,
    listAll: async () => [PAGE],
    ...overrides,
  };
}

describe('CmsService', () => {
  it('creates a page (200), duplicate slug -> 409', async () => {
    const service = new CmsService(repo());
    const page = await service.create({ slug: 'about', title: 'About', body: 'Content' });
    expect(page.id).toBe('page-1');
    const dupService = new CmsService(repo({ create: async () => undefined }));
    await expect(
      dupService.create({ slug: 'about', title: 'About', body: 'Content' }),
    ).rejects.toBeInstanceOf(DuplicateSlugError);
  });

  it('returns 200 on published page and 404 on draft', async () => {
    const published = new CmsService(
      repo({ findBySlug: async () => ({ ...PAGE, status: 'published' }) }),
    );
    const draft = new CmsService(repo());
    const page = await published.getPublicPageBySlug('about');
    expect(page.status).toBe('published');
    await expect(published.getPublicPageBySlug('about')).resolves.toMatchObject({
      status: 'published',
    });
    await expect(draft.getPublicPageBySlug('about')).rejects.toBeInstanceOf(PageNotPublishedError);
  });

  it('returns 404 when page does not exist', async () => {
    const service = new CmsService(repo({ findBySlug: async () => undefined }));
    await expect(service.getPublicPageBySlug('missing')).rejects.toBeInstanceOf(PageNotFoundError);
  });

  it('publish/unpublish change status', async () => {
    const service = new CmsService(repo());
    expect((await service.publish('page-1')).status).toBe('published');
    expect((await service.unpublish('page-1')).status).toBe('draft');
  });
});
