import {useEffect,useRef,useState,ReactNode} from 'react';
import {Config,Entry,weekRange,currentWeek} from '../lib/model';
import {parseWeekPaste} from './week-paste';
export function ScrollTable({children}:{children:ReactNode}){const top=useRef<HTMLDivElement>(null),body=useRef<HTMLDivElement>(null),[width,setWidth]=useState(1000);useEffect(()=>{const b=body.current;if(!b)return;const measure=()=>{setWidth(b.scrollWidth);b.querySelectorAll('th').forEach(th=>th.classList.toggle('current-week',th.textContent?.trim()===currentWeek()));};measure();const ro=new ResizeObserver(measure);ro.observe(b);if(b.firstElementChild)ro.observe(b.firstElementChild);return()=>ro.disconnect();},[children]);return <div className="scroll-table-wrap"><div className="top-scroll" ref={top} onScroll={()=>{if(body.current&&top.current)body.current.scrollLeft=top.current.scrollLeft;}} aria-label="Horizontal table scroll" tabIndex={0}><div style={{width,height:1}}/></div><div className="table-scroll" ref={body} onScroll={()=>{if(top.current&&body.current)top.current.scrollLeft=body.current.scrollLeft;}}>{children}</div></div>;}
export function WeekRange({config,from,to,onChange,min}:{config:Config;from:string;to?:string;onChange:(from:string,to:string)=>void;min?:string}){const end=to||weekRange(config,from).at(-1);return <div className="week-range"><label>From week<select value={from} onChange={e=>onChange(e.target.value,'')}>{config.weeks.filter(w=>!min||w>=min).map(w=><option key={w}>{w}</option>)}</select></label><label>To week<select value={end} onChange={e=>onChange(from,e.target.value)}>{config.weeks.filter(w=>w>=from).map(w=><option key={w}>{w}</option>)}</select></label><button type="button" className="secondary" onClick={()=>onChange(from,'')}>13 weeks</button></div>;}
export function MoveDialog({row,config,start,min,onClose,onSave}:{row:Entry;config:Config;start:string;min:string;onClose:()=>void;onSave:(x:any)=>Promise<void>}){const expected=row.kind==='project'&&row.team.startsWith('Expected · ');const [target,setTarget]=useState(''),[from,setFrom]=useState(start<min?min:start),[to,setTo]=useState(''),[busy,setBusy]=useState(false),[error,setError]=useState('');return <div className="modal-backdrop"><section className="modal" role="dialog" aria-label="Move input"><header><h2>Move {row.payload.project||row.payload.name}</h2><button onClick={onClose}>Close</button></header><div className="modal-body"><p>{expected?'Confirm this expected project and move all its related planned, delay and modification rows to the selected team. All weekly values and history are preserved; no duplicate is created.':`From team: ${row.team}. Only the selected weeks move. Other weeks stay in this team. The destination receives a separate row with the same work type.`}</p><label>Destination team<select value={target} onChange={e=>setTarget(e.target.value)}><option value="">Select team…</option>{config.teams.filter(t=>t!==row.team&&(!expected||!t.startsWith('Expected · '))).map(t=><option key={t}>{t}</option>)}</select></label><div hidden={expected}><WeekRange config={config} from={from} to={to} min={min} onChange={(f,t)=>{setFrom(f);setTo(t);}}/><p>{weekRange(config,from,to).length} weeks: {from} – {weekRange(config,from,to).at(-1)}</p></div>{error&&<p role="alert">{error}</p>}<button disabled={!target||busy} onClick={async()=>{setBusy(true);try{await onSave({...row,action:expected?'assign':'move',targetTeam:target,fromWeek:from,toWeek:weekRange(config,from,to).at(-1)});onClose();}catch(e:any){setError(e.message);}finally{setBusy(false);}}}>{expected?'Confirm project and move to team':'Move selected weeks'}</button></div></section></div>;}
const projectKeys=['project','client','category','structure','workType','software','status','responsible'];
export function parseProjectPaste(text:string,weeks:string[]){const rows=text.replace(/\r\n?/g,'\n').replace(/\n$/,'').split('\n');if(rows.length!==1)throw Error('Copy one row without headings.');const cells=rows[0].split('\t');if(cells.length!==8+weeks.length)throw Error(`Expected 8 project-detail cells followed by ${weeks.length} weekly values.`);const p:any=Object.fromEntries(projectKeys.map((k,i)=>[k,cells[i].trim()]));p.weeks=parseWeekPaste(cells.slice(8).join('\t'),weeks);return p;}
export function ProjectPaste({weeks,onApply}:{weeks:string[];onApply:(p:any)=>void}){const [text,setText]=useState(''),[message,setMessage]=useState('');return <details className="excel-paste"><summary>Paste project details and weekly hours</summary><p>Copy one row in this column order: Project, Client, Project category, Structure, Work type, Software, Status, Responsible person, then {weeks.length} weekly values ({weeks[0]}–{weeks.at(-1)}). No headings. Blank weekly cells become zero.</p><textarea rows={3} aria-label="Project details from Excel" value={text} onChange={e=>setText(e.target.value)}/><button type="button" onClick={()=>{try{onApply(parseProjectPaste(text,weeks));setMessage('Applied to the form. Review the details and weekly values, then Save input.');}catch(e:any){setMessage(e.message);}}}>Apply to form</button><p role="status">{message}</p></details>;}
export function BulkProductivity({rows,config,start,min,onSave,onClose}:{rows:Entry[];config:Config;start:string;min:string;onSave:(changes:any[])=>Promise<void>;onClose:()=>void}){const [from,setFrom]=useState(start<min?min:start),[to,setTo]=useState(start<min?min:start),[text,setText]=useState(''),[values,setValues]=useState<number[]|null>(null),[error,setError]=useState(''),[busy,setBusy]=useState(false);const weeks=weekRange(config,from,to);return <div className="modal-backdrop"><section className="modal" role="dialog" aria-label="Paste team productivity"><header><h2>Paste team productivity column</h2><button onClick={onClose}>Close</button></header><div className="modal-body"><p>Paste one value per employee, in the exact order listed below. Includes all active employees in this team, across all pages. Each value will be applied to every selected week. Blank cells become zero; other weeks remain unchanged.</p><WeekRange config={config} from={from} to={to} min={min} onChange={(f,t)=>{setFrom(f);setTo(t);setValues(null);}}/><textarea rows={5} aria-label="Employee productivity column" value={text} onChange={e=>{setText(e.target.value);setValues(null);}}/><button onClick={()=>{try{const lines=text.replace(/\r\n?/g,'\n').replace(/\n$/,'').split('\n');if(lines.length!==rows.length||lines.some(l=>l.includes('\t')))throw Error(`Paste exactly ${rows.length} cells in one column.`);setValues(lines.map(l=>parseWeekPaste(l,['value']).value));setError('');}catch(e:any){setError(e.message);}}}>Preview values</button><table><thead><tr><th>Employee</th><th>Client category</th><th>New value for each selected week</th></tr></thead><tbody>{rows.map((r,i)=><tr key={r.id}><td>{i+1}. {r.payload.name}</td><td>{r.payload.clientCategory||'Unassigned'}</td><td>{values?values[i]:'—'}</td></tr>)}</tbody></table>{error&&<p role="alert">{error}</p>}<button disabled={!values||busy||!rows.length} onClick={async()=>{setBusy(true);try{await onSave(rows.map((r,i)=>({...r,payload:{...r.payload,weeks:{...r.payload.weeks,...Object.fromEntries(weeks.map(w=>[w,values![i]]))}}})));onClose();}catch(e:any){setError(e.message);}finally{setBusy(false);}}}>Save {rows.length} employees · {weeks.length} weeks</button></div></section></div>;}
export function TeamNames({config,revision,onSave}:{config:Config;revision:number;onSave:(team:string,names:string[],revision:number)=>Promise<void>}){const [draftRevision,setDraftRevision]=useState<number|null>(null);const [team,setTeam]=useState(config.teams[0]),[text,setText]=useState(''),[message,setMessage]=useState(''),[busy,setBusy]=useState(false);return <section className="field-card"><h2>Responsible persons by team</h2><label>Team<select value={team} onChange={e=>{setTeam(e.target.value);setText('');setMessage('');setDraftRevision(null);}}>{config.teams.map(t=><option key={t}>{t}</option>)}</select></label><p>Paste one name per line, or upload a UTF-8 CSV/text file containing one column without a header. Saving replaces this team's dropdown list. Existing project assignments are retained.</p><input type="file" accept=".csv,.txt,.tsv" onChange={async e=>{const f=e.target.files?.[0];if(f){setDraftRevision(revision);setText((await f.text()).replace(/^\uFEFF/,''));}}}/><textarea rows={5} aria-label="Responsible person names" value={text} onChange={e=>{if(draftRevision===null)setDraftRevision(revision);setText(e.target.value);}}/><p>Current list: {(config.teamResponsibles?.[team]||[]).join(', ')||'No names uploaded'}</p><button disabled={busy} onClick={async()=>{const names=text.split(/\r?\n/).map(n=>n.trim().replace(/^"(.*)"$/,'$1')).filter(Boolean);if(names.some(n=>n.includes('\t')||n.includes(','))){setMessage('Use one name per line, without extra columns.');return;}if(!names.length&&!window.confirm('Clear this team’s responsible person list?'))return;setBusy(true);try{await onSave(team,names,draftRevision??revision);setMessage('Team list saved.');setText('');setDraftRevision(null);}catch(e:any){setMessage(e.message);}finally{setBusy(false);}}}>Save team list</button><p role="status">{message}</p></section>;}
