import '../../../../src/qa/loadEnv';
import fs from 'node:fs';
import path from 'node:path';
import {expect,type Browser,type BrowserContext,type Page,type TestInfo} from '@playwright/test';
import {getRuntimeQaEnv} from '../../../../src/qa/env';
import {createStorageStateForRole} from '../../../../src/qa/storageState';

export type Role='CO'|'BO'|'VE';
export type Check={id:string;role:Role;combination:string;status:'PASS'|'FAIL'|'BLOCKED';detail:string;evidence:string[];observedAt?:string};
export const root='qa-results/issues/4298/dev';
export const recovery='.auth/recovery-4298';
export const labels={CO:'법인',BO:'영업점',VE:'가맹점'};
export const names={CO:'부서상용버전',BO:'부서별 운영상태 관리 영업',VE:'ve1'};
export const presetIds={CO:708,BO:753,VE:684};
export const keys={'스토어 거래조회':'STORE_READ_TRANSACTION','스토어 정산조회':'STORE_READ_SETTLEMENT','매출집계 조회':'READ_SALES_TALLY','스토어 지갑내역':'STORE_READ_REMITTANCE','스토어 송금하기':'STORE_SEND_REMITTANCE','링크발송조회':'READ_LINK_PAYMENT','링크샵':'LINKSHOP'} as Record<string,string>;
export const adminEnv=()=>getRuntimeQaEnv('dev','admin','Q4298_ADMIN');
export const storeEnv=(role:Role)=>getRuntimeQaEnv('dev','store',`Q4298_${role}`);
export function selected(p:any):string[]{const ids:string[]=[];const visit=(x:any[])=>{for(const i of x??[]){ids.push(i.id);visit(i.children??[])}};for(const g of [...p.permissions.menu,...p.permissions.task])visit(g.permissions);return [...new Set(ids)].sort();}
export async function preset(c:BrowserContext,role:Role){const r=await c.request.get(`https://api-dev.biscuitpay.com/api/v1/admin/role-permission-presets/${presetIds[role]}`,{headers:{'X-TENANT-ID':adminEnv().tenantId!}});expect(r.ok()).toBeTruthy();return (await r.json()).payload;}
export async function openPreset(p:Page,role:Role){await p.goto(`${adminEnv().baseUrl}/admin/member-preset?tenantId=redacted).tenantId}`,{waitUntil:'domcontentloaded'});await p.getByRole('button',{name:labels[role],exact:true}).last().click();await p.getByText(names[role],{exact:true}).last().click();await p.getByRole('button',{name:'기능 권한',exact:true}).last().click();await p.getByRole('checkbox',{name:'스토어 거래조회',exact:true}).waitFor();}
export async function save(p:Page,role:Role,settings:Record<string,boolean>,reason:string){
 for(const [label,value]of Object.entries(settings))await p.getByRole('checkbox',{name:label,exact:true}).setChecked(value);
 const response=p.waitForResponse(r=>r.request().method()==='PATCH'&&new URL(r.url()).pathname.endsWith(`/role-permission-presets/${presetIds[role]}`));
 await p.getByRole('button',{name:'수정',exact:true}).last().click();await p.locator('textarea.swal2-textarea').fill(`#4298 QA ${reason}`);await p.getByRole('button',{name:'확인',exact:true}).last().click();
 const r=await response;expect(r.ok()).toBeTruthy();expect((await r.json()).result.code).toBe(200);
 await expect(p.locator('.swal2-container')).toHaveCount(0);
}
export async function dismissNotice(p:Page){const hide=p.getByRole('button',{name:'오늘 더 이상 보지 않기',exact:true});if(await hide.isVisible()) {await hide.click();await hide.waitFor({state:'hidden'});}}
export async function settled(p:Page){await p.waitForLoadState('domcontentloaded');await p.waitForTimeout(1700);await p.getByText('로딩 중...',{exact:true}).first().waitFor({state:'hidden',timeout:60000});await dismissNotice(p);}
export async function go(p:Page,route:string){await p.goto(new URL(route,storeEnv('CO').baseUrl).href,{waitUntil:'domcontentloaded',timeout:60000});await settled(p);}
export async function screen(p:Page,info:TestInfo,name:string){const file=path.join(root,'evidence',`${name}.png`);fs.mkdirSync(path.dirname(file),{recursive:true});if(p.url().includes('admin-dev')&&await p.getByRole('checkbox',{name:'스토어 거래조회',exact:true}).count())await p.getByRole('checkbox',{name:'스토어 거래조회',exact:true}).scrollIntoViewIfNeeded();const mask=p.getByRole('button',{name:adminEnv().username??'__none__',exact:true});await p.screenshot({path:file,animations:'disabled',timeout:15000,mask:[...(await mask.count()?[mask]:[]),p.getByText(/(?:\uC740\uD589|\uC99D\uAD8C)\s+[\d* -]{8,}/)]});await info.attach(name,{path:file,contentType:'image/png'});return file;}
export async function fresh(browser:Browser,role:Role){await createStorageStateForRole({application:'store',environment:'dev',role:`Q4298_${role}`});const c=await browser.newContext({storageState:storeEnv(role).storageState,viewport:{width:1280,height:900}});const p=await c.newPage();p.setDefaultTimeout(10000);p.setDefaultNavigationTimeout(60000);return p;}
export function record(rows:Check[],role:Role,combination:string,ids:string|string[],ok:boolean,detail:string,evidence:string[]=[]){for(const id of typeof ids==='string'?[ids]:ids)rows.push({id,role,combination,status:ok?'PASS':'FAIL',detail,evidence,observedAt:new Date().toISOString()});}
export function blocked(rows:Check[],role:Role,id:string,detail:string,evidence:string[]=[]){rows.push({id,role,combination:'data/precondition',status:'BLOCKED',detail,evidence});}
export async function denied(p:Page,route:string,info:TestInfo,name:string){await go(p,route);const isDenied=await p.getByText('접근 제한',{exact:true}).isVisible();const shot=await screen(p,info,name);if(isDenied){await p.getByRole('button',{name:'확인',exact:true}).last().click();await expect(p).toHaveURL(/\.com\/?$/);await settled(p);}return {ok:isDenied&&new URL(p.url()).pathname==='/',shot};}
export function persist(role:Role,rows:Check[]){fs.mkdirSync(`${root}/matrix`,{recursive:true});fs.writeFileSync(`${root}/matrix/${role}.json`,JSON.stringify(rows,null,2)+'\n');}
export async function homeSnapshot(p:Page){const result:Record<string,string[]>={};for(const label of ['금일매출','전일매출','정산금','총 정산예정금','지갑잔고'])result[label]=await p.getByText(label,{exact:true}).evaluateAll(es=>es.map(e=>(e.parentElement?.textContent??'').replace(/\s+/g,' ').trim()));return result;}
