import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
import { browser } from './browser.mjs';
const publicDir = resolve(import.meta.dirname, '../src/public');
const url = name => pathToFileURL(join(publicDir, name)).href;
const project = { id: '20000000-0000-4000-8000-000000000002', name: 'Example project', repo: null };
for (const width of [1440, 390]) {
test(`archive controls have shared button styling at ${width}px`, async t => {
const dir = await mkdtemp(join(tmpdir(), 'archive-style-'));
const html = `
${['shared/app.css', 'tokens.css', 'chat.css', 'shell.css', 'project-archive.css'].map(x => ``).join('')}
`;
const fixture = join(dir, 'fixture.html');
await writeFile(fixture, html);
const b = await browser();
t.after(() => b.close());
t.after(() => rm(dir, { recursive: true, force: true }));
await b.viewport(width, 1000);
await b.navigate(pathToFileURL(fixture).href);
await b.evaluate(`window.MosaicChat={projectPath:id=>'#/'+id}; window.fetch=async()=>({ok:true,json:async()=>({rows:[{...${JSON.stringify(project)},archived:true}]})}); window.renderList=()=>{const e=document.querySelector('#list');e.replaceChildren();MosaicProjectArchive.mount(e,{kind:'list',canSend:true})};window.addEventListener('hashchange',renderList);window.renderProject=archived=>{const e=document.querySelector('#project');e.replaceChildren();MosaicProjectArchive.mount(e,{kind:'project',canSend:true,id:${JSON.stringify(project.id)},projects:[{...${JSON.stringify(project)},archived}]})};renderProject(false);renderList();true`);
await b.evaluate(`document.querySelector('#project-archive-toggle').click();true`);
await b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(document.querySelector('#project-archive-list button'))return;await new Promise(r=>setTimeout(r,20))}throw Error('archived row missing')})()`);
if (process.env.ARCHIVE_STYLE_SHOTS) await b.screenshot(join(process.env.ARCHIVE_STYLE_SHOTS, `${process.env.ARCHIVE_STYLE_PHASE}-${width}.png`));
const inspect = async selector => b.evaluate(`(()=>{const e=document.querySelector(${JSON.stringify(selector)}),s=getComputedStyle(e);return {height:e.getBoundingClientRect().height,radius:s.borderTopLeftRadius,background:s.backgroundColor,classes:e.className}})()`);
const defaults = await inspect('#default');
const check = (s, label) => {
assert.ok(s.height >= 44, `${label} height: ${s.height}`);
assert.equal(s.radius, '6px', `${label} radius`);
assert.notEqual(s.background, defaults.background, `${label} background`);
assert.ok(s.classes.split(/\s+/).includes('btn'), `${label} shared class`);
};
const archive = await inspect('#project-archive-button');
const row = await inspect('#project-archive-list button');
assert.equal(await b.evaluate(`document.querySelector('#project-archive-list a button') === null && document.querySelector('#project-archive-list li > a + button') !== null`), true, 'Unarchive is a sibling of the card link');
check(archive, 'Archive'); check(row, 'list Unarchive'); check(await inspect('#project-archive-toggle'), 'toggle');
assert.notEqual(archive.background, row.background, 'Archive has a distinct background');
// The danger tint must preserve readable text in every palette and appearance.
const contrastFailures = await b.evaluate(`(()=>{
const button=document.querySelector('#project-archive-button'), root=document.documentElement;
const canvas=document.createElement('canvas'), ctx=canvas.getContext('2d');
const rgb=color=>{ctx.clearRect(0,0,1,1);ctx.fillStyle=color;ctx.fillRect(0,0,1,1);return [...ctx.getImageData(0,0,1,1).data].slice(0,3).map(v=>{v/=255;return v<=.04045?v/12.92:((v+.055)/1.055)**2.4})};
const luminance=c=>{const [r,g,b]=rgb(c);return .2126*r+.7152*g+.0722*b};
const failures=[];
for(const palette of ['harbor','atlantic','aubergine','carmine','cobalt','graphite','grove','mineral','rosewood','terracotta']) for(const mode of ['light','dim','dark']) {
root.dataset.palette=palette;root.dataset.mode=mode;
const s=getComputedStyle(button), a=luminance(s.color), b=luminance(s.backgroundColor), ratio=(Math.max(a,b)+.05)/(Math.min(a,b)+.05);
if(ratio<4.5)failures.push({palette,mode,ratio});
}
root.dataset.palette='harbor';root.dataset.mode='light';button.focus();
const s=getComputedStyle(button);if(s.outlineStyle==='none'||parseFloat(s.outlineWidth)<2)failures.push({focus:s.outline});
return failures;
})()`);
assert.deepEqual(contrastFailures, [], 'danger button text contrast and focus ring');
await b.evaluate('renderProject(true);true');
check(await inspect('#project-archive-button'), 'project Unarchive');
});
}