import assert from 'node:assert/strict';
import test from 'node:test';
import { createDbPool, initSchema, isDatabaseConfigured } from './db.mjs';
import { createPlazaPostService, formatPostRow, mapPlazaError } from './plaza-posts.mjs';
import { createPlazaOpsService } from './plaza-ops.mjs';
import {
  createIntegrationUser,
  createOnlinePublication,
  getPlazaCategoryId,
  setOpsRole,
} from './plaza-test-fixtures.mjs';

const integrationEnabled = isDatabaseConfigured();

function buildPlazaServices(pool) {
  const posts = createPlazaPostService(pool, {
    autoApprove: false,
    formatPostRow,
  });
  const ops = createPlazaOpsService(pool, {
    formatPostRow,
    reviewPost: (...args) => posts.reviewPost(...args),
  });
  return { posts, ops };
}

test(
  'integration: publish → pending → approve → visible in feed',
  { skip: !integrationEnabled && 'MySQL not configured (set MYSQL_* or DATABASE_URL)' },
  async () => {
    const pool = createDbPool();
    await initSchema(pool);
    const { posts, ops } = buildPlazaServices(pool);
    await posts.ensureCategories();

    const author = await createIntegrationUser(pool, 'author');
    const reviewer = await createIntegrationUser(pool, 'reviewer');
    await setOpsRole(pool, reviewer.id, 'reviewer');
    const { publicationId } = await createOnlinePublication(pool, author.id);
    const categoryId = await getPlazaCategoryId(pool);
    assert.ok(categoryId, 'plaza categories should be seeded');

    const created = await posts.createPost(author.id, {
      publication_id: publicationId,
      category_id: categoryId,
      tags: ['integration'],
    });
    assert.equal(created.status, 'pending_review');

    const pendingFeed = await posts.listFeed({ sort: 'hot' });
    assert.ok(!pendingFeed.posts.some((post) => post.id === created.id));

    const reviewed = await ops.reviewPostAsOps(reviewer.id, created.id, 'approve');
    assert.equal(reviewed.status, 'published');

    const [auditRows] = await pool.query(
      `SELECT action FROM ops_audit_log WHERE target_type = 'post' AND target_id = ?`,
      [created.id],
    );
    assert.equal(auditRows.length, 1);
    assert.equal(auditRows[0].action, 'approve_post');

    const publishedFeed = await posts.listFeed({ sort: 'hot' });
    assert.ok(publishedFeed.posts.some((post) => post.id === created.id));

    await pool.end();
  },
);

test(
  'integration: non-author cannot hide another users post',
  { skip: !integrationEnabled && 'MySQL not configured (set MYSQL_* or DATABASE_URL)' },
  async () => {
    const pool = createDbPool();
    await initSchema(pool);
    const { posts, ops } = buildPlazaServices(pool);
    await posts.ensureCategories();

    const author = await createIntegrationUser(pool, 'owner');
    const other = await createIntegrationUser(pool, 'other');
    const reviewer = await createIntegrationUser(pool, 'mod');
    await setOpsRole(pool, reviewer.id, 'reviewer');

    const { publicationId } = await createOnlinePublication(pool, author.id);
    const categoryId = await getPlazaCategoryId(pool);
    const created = await posts.createPost(author.id, {
      publication_id: publicationId,
      category_id: categoryId,
    });
    await ops.reviewPostAsOps(reviewer.id, created.id, 'approve');

    await assert.rejects(() => posts.hidePost(other.id, created.id), (error) => {
      assert.equal(error.code, 'POST_NOT_FOUND');
      return true;
    });
    assert.equal(mapPlazaError({ code: 'POST_NOT_FOUND' }), 404);

    await pool.end();
  },
);

test(
  'integration: duplicate publication publish returns ALREADY_PUBLISHED',
  { skip: !integrationEnabled && 'MySQL not configured (set MYSQL_* or DATABASE_URL)' },
  async () => {
    const pool = createDbPool();
    await initSchema(pool);
    const { posts } = buildPlazaServices(pool);
    await posts.ensureCategories();

    const author = await createIntegrationUser(pool, 'dup');
    const { publicationId } = await createOnlinePublication(pool, author.id);
    const categoryId = await getPlazaCategoryId(pool);

    await posts.createPost(author.id, {
      publication_id: publicationId,
      category_id: categoryId,
    });

    await assert.rejects(
      () =>
        posts.createPost(author.id, {
          publication_id: publicationId,
          category_id: categoryId,
        }),
      (error) => {
        assert.equal(error.code, 'ALREADY_PUBLISHED');
        return true;
      },
    );
    assert.equal(mapPlazaError({ code: 'ALREADY_PUBLISHED' }), 409);

    await pool.end();
  },
);
