import assert from 'node:assert/strict';
import { test } from 'node:test';
import { MINISTRY_TRANSLATIONS } from './ministry.translation.seed';
import { PSWG_TRANSLATIONS, CDC_TRANSLATIONS, CEFP_TRANSLATIONS, CDCGPSF_TRANSLATIONS } from './index';
import { seedTranslationItems } from './translation-seed.runner';
import { meetingSummaryI18n } from '../../../../frontend/features/ministry/meeting-summary/meeting-summary-i18n';
import {
  meetingSummaryTranslationKey,
  meetingSummaryOverrideFromDictionary,
  resolveMeetingSummaryText,
  unwrapMeetingSummaryDictionary,
  meetingSummaryOwner,
  fetchMeetingSummaryDictionary,
} from '../../../../frontend/features/ministry/meeting-summary/meeting-summary-translations';
import { fetchMeetingSummaryTranslations } from '../../../../frontend/features/pswg/meeting-summary/meeting-summary-translation-service';

const items = MINISTRY_TRANSLATIONS.filter(
  (item) => item.page === 'meeting_summary',
);

test('shared summary labels are seeded separately for each module with a summary page', () => {
  for (const seeds of [PSWG_TRANSLATIONS, CDC_TRANSLATIONS, CEFP_TRANSLATIONS, CDCGPSF_TRANSLATIONS]) {
    const page = seeds.filter(item => item.page === 'meeting_summary');
    if (!page.length) continue;
    for (const ministryItem of items) {
      const item = page.find(row => row.translationKey === ministryItem.translationKey);
      assert.ok(item, `${seeds[0].module}/${ministryItem.translationKey}`);
      assert.ok(item.englishText.trim() && item.khmerText.trim());
    }
  }
});

test('shared summary requests use the route owner, including Khmer print language', async (t) => {
  assert.equal(meetingSummaryOwner('/admin/translation-management'), null);
  t.mock.method(globalThis, 'fetch', async (input) => {
    const url = new URL(String(input));
    assert.equal(url.searchParams.get('page'), 'meeting_summary');
    assert.equal(url.searchParams.get('language'), 'km');
    return new Response(JSON.stringify({data:{translations:{page_title:url.searchParams.get('module')}}}));
  });
  for (const route of ['ministry', 'pswg', 'cdc', 'cefp', 'cdc-gpsf']) {
    const owner = meetingSummaryOwner(`/${route}/meeting-summary/1`)!;
    assert.equal(owner, route === 'cdc-gpsf' ? 'cdcgpsf' : route);
    const dictionary = await fetchMeetingSummaryDictionary('km', undefined, owner);
    assert.equal(dictionary.page_title, owner);
  }
});

function flatten(value: object, prefix = ''): Record<string, string> {
  return Object.assign(
    {},
    ...Object.entries(value).map(([key, entry]) => {
      const path = prefix ? `${prefix}.${key}` : key;
      return typeof entry === 'string'
        ? { [path]: entry }
        : flatten(entry, path);
    }),
  );
}

test('every English/Khmer label has exactly one matching seed key', () => {
  const en = flatten(meetingSummaryI18n.en);
  const km = flatten(meetingSummaryI18n.km);
  assert.deepEqual(Object.keys(en).sort(), Object.keys(km).sort());
  assert.equal(
    new Set(items.map((item) => item.translationKey)).size,
    items.length,
  );
  for (const [path, englishText] of Object.entries(en)) {
    const item = items.find(
      (entry) => entry.translationKey === meetingSummaryTranslationKey(path),
    );
    assert.ok(item, `Missing seed: ${path}`);
    assert.equal(item.englishText, englishText);
    assert.equal(item.khmerText, km[path]);
    assert.equal(item.isActive, true);
  }
  assert.equal(items.length, Object.keys(en).length + 1); // existing sidebar title
  assert.equal(
    items.find((item) => item.translationKey === 'title')?.englishText,
    'Meeting Summary',
  );
});

test('API dictionary updates nested labels and keeps missing/empty labels', () => {
  const resolved = resolveMeetingSummaryText(meetingSummaryI18n.en, {
    page_title: 'Admin heading',
    'issue_dialog.detail_title': 'Admin issue details',
    'status_labels.draft': 'Admin draft',
    'common.print': '',
    'columns.no': '   ',
    'unknown.key': 'Ignored',
  });
  assert.equal(resolved.title, 'Admin heading');
  assert.equal(resolved.issueDialog.detailTitle, 'Admin issue details');
  assert.equal(resolved.statusLabels.DRAFT, 'Admin draft');
  assert.equal(resolved.common.print, 'Print');
  assert.equal(resolved.columns.no, 'No.');
  assert.equal(meetingSummaryI18n.en.title, 'All Meeting Summary');
  assert.equal('unknown' in resolved, false);
});

test('PSWG partial overrides retain shared labels without mutating defaults', () => {
  const text = resolveMeetingSummaryText(
    meetingSummaryI18n.km,
    {},
    {
      details: { meetingRequest: 'PSWG override' },
    },
  );
  assert.equal(text.details.meetingRequest, 'PSWG override');
  assert.equal(text.details.location, meetingSummaryI18n.km.details.location);
  assert.equal(text.common.print, meetingSummaryI18n.km.common.print);
});

test('dictionary accepts both response envelopes and rejects invalid values', () => {
  const dictionary = {
    translations: { page_title: 'Admin', bad: null, empty: ' ' },
  };
  assert.deepEqual(unwrapMeetingSummaryDictionary({ data: dictionary }), {
    page_title: 'Admin',
  });
  assert.deepEqual(
    unwrapMeetingSummaryDictionary({ data: { data: dictionary } }),
    { page_title: 'Admin' },
  );
  assert.deepEqual(unwrapMeetingSummaryDictionary(null), {});
});

test('PSWG API overrides never replace missing shared labels with static defaults', async (t) => {
  t.mock.method(globalThis, 'fetch', async (input) => {
    const kh = new URL(String(input)).searchParams.get('language') === 'km';
    return new Response(JSON.stringify({data:{translations:{
      'details.meeting_request': kh ? 'សំណើ PSWG' : 'PSWG request',
      'columns.id': kh ? 'លេខ PSWG' : 'PSWG number',
      'view_page.title': kh ? 'ចំណងជើង PSWG' : 'Admin PSWG heading',
    }}}));
  });
  for (const lang of ['en', 'kh'] as const) {
    const pswg = await fetchMeetingSummaryTranslations(lang);
    assert.equal(
      pswg.text.viewPage.title,
      lang === 'en' ? 'Admin PSWG heading' : 'ចំណងជើង PSWG',
    );
    assert.equal(pswg.sharedTextOverride.issueDialog, undefined);
    assert.equal(pswg.sharedTextOverride.common, undefined);
    const text = resolveMeetingSummaryText(
      meetingSummaryI18n[lang === 'kh' ? 'km' : 'en'],
      {
        'details.meeting_request': 'Ministry request',
        'issue_dialog.detail_title': 'Admin shared issue dialog',
        'common.print': 'Admin shared print',
        'participants.title': 'Admin shared participants',
        'print.title': 'Admin report title',
      },
      pswg.sharedTextOverride,
    );
    assert.equal(
      text.details.meetingRequest,
      lang === 'en' ? 'PSWG request' : 'សំណើ PSWG',
    );
    assert.equal(text.columns.no, lang === 'en' ? 'PSWG number' : 'លេខ PSWG');
    assert.equal(text.issueDialog.detailTitle, 'Admin shared issue dialog');
    assert.equal(text.common.print, 'Admin shared print');
    assert.equal(text.participants.title, 'Admin shared participants');
    assert.equal(text.print.title, 'Admin report title');
  }
});

test('PSWG API failure keeps Ministry API translations available', async (t) => {
  t.mock.method(globalThis, 'fetch', async () => {
    throw new Error('offline');
  });
  const pswg = await fetchMeetingSummaryTranslations('en');
  assert.deepEqual(pswg.sharedTextOverride, {});
  const text = resolveMeetingSummaryText(
    meetingSummaryI18n.en,
    {
      'details.meeting_request': 'Admin Ministry request',
    },
    pswg.sharedTextOverride,
  );
  assert.equal(text.details.meetingRequest, 'Admin Ministry request');
});

test('blank overrides do not mask Ministry translations', () => {
  const override = meetingSummaryOverrideFromDictionary({
    'common.print': ' ',
    'details.meeting_request': '',
    'unknown.key': 'ignore',
  });
  assert.deepEqual(override, {});
});

test('seeding is repeatable and preserves existing Admin translations', async () => {
  const rows = new Map<string, { id: number; englishText: string }>();
  const existing = items[0];
  rows.set(existing.translationKey, { id: 1, englishText: 'Admin edited' });
  const db = {
    translation: {
      findUnique: async ({
        where,
      }: {
        where: { module_page_translationKey: { translationKey: string } };
      }) => rows.get(where.module_page_translationKey.translationKey) ?? null,
      create: async ({
        data,
      }: {
        data: { translationKey: string; englishText: string };
      }) => {
        const row = { id: rows.size + 1, englishText: data.englishText };
        rows.set(data.translationKey, row);
        return row;
      },
    },
  };
  const first = await seedTranslationItems(db, 'ministry', items);
  assert.equal(first.created, items.length - 1);
  assert.equal(first.kept, 1);
  const second = await seedTranslationItems(db, 'ministry', items);
  assert.equal(second.created, 0);
  assert.equal(second.kept, items.length);
  assert.equal(rows.get(existing.translationKey)?.englishText, 'Admin edited');
});
