import type pg from 'pg';
import type { CmsRepository } from '../domain/ports.js';
import type { CreatePageInput, Page, PageStatus, UpdatePageInput } from '../domain/page.js';

interface PageRow {
  id: string;
  slug: string;
  title: string;
  body: string;
  status: PageStatus;
  created_at: Date;
  updated_at: Date;
}

export class PgCmsRepository implements CmsRepository {
  constructor(private readonly pool: pg.Pool) {}

  async create(input: CreatePageInput): Promise<Page | undefined> {
    const result = await this.pool.query<PageRow>(
      `INSERT INTO cms_pages (slug, title, body)
       VALUES ($1, $2, $3)
       ON CONFLICT (slug) DO NOTHING
       RETURNING *`,
      [input.slug, input.title, input.body],
    );
    const row = result.rows[0];
    return row ? toPage(row) : undefined;
  }

  async update(id: string, patch: UpdatePageInput): Promise<Page | undefined> {
    const set: string[] = [];
    const values: unknown[] = [];
    if (patch.slug !== undefined) {
      values.push(patch.slug);
      set.push(`slug = $${values.length}`);
    }
    if (patch.title !== undefined) {
      values.push(patch.title);
      set.push(`title = $${values.length}`);
    }
    if (patch.body !== undefined) {
      values.push(patch.body);
      set.push(`body = $${values.length}`);
    }
    if (set.length === 0) return this.findById(id);
    values.push(id);
    const result = await this.pool.query<PageRow>(
      `UPDATE cms_pages SET ${set.join(', ')}, updated_at = now() WHERE id = $${values.length} RETURNING *`,
      values,
    );
    const row = result.rows[0];
    return row ? toPage(row) : undefined;
  }

  async setStatus(id: string, status: PageStatus): Promise<Page | undefined> {
    const result = await this.pool.query<PageRow>(
      `UPDATE cms_pages SET status = $2, updated_at = now() WHERE id = $1 RETURNING *`,
      [id, status],
    );
    const row = result.rows[0];
    return row ? toPage(row) : undefined;
  }

  async findBySlug(slug: string): Promise<Page | undefined> {
    const result = await this.pool.query<PageRow>('SELECT * FROM cms_pages WHERE slug = $1', [
      slug,
    ]);
    const row = result.rows[0];
    return row ? toPage(row) : undefined;
  }

  async findById(id: string): Promise<Page | undefined> {
    const result = await this.pool.query<PageRow>('SELECT * FROM cms_pages WHERE id = $1', [id]);
    const row = result.rows[0];
    return row ? toPage(row) : undefined;
  }

  async listAll(): Promise<Page[]> {
    const result = await this.pool.query<PageRow>(
      'SELECT * FROM cms_pages ORDER BY created_at DESC',
    );
    return result.rows.map(toPage);
  }
}

function toPage(row: PageRow): Page {
  return {
    id: row.id,
    slug: row.slug,
    title: row.title,
    body: row.body,
    status: row.status,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  };
}
