"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { adminLogout, adminRequest, adminSession, adminUploadFile, AdminSummary, AdminUser, UploadedImage } from "../lib/admin-api";
import styles from "./admin.module.css";

type Tab = "overview" | "portfolio" | "taxonomy" | "banners" | "partners";
type Row = Record<string, any>;
type UploadRow = { key: string; file: File; preview: string; valid: boolean; width: number; height: number; progress: number; status: "queued" | "uploading" | "uploaded" | "error"; asset?: UploadedImage; error?: string };
const tabs: Array<{ id: Tab; label: string; code: string }> = [{id:"overview",label:"Tổng quan",code:"00"},{id:"portfolio",label:"Tác phẩm",code:"01"},{id:"taxonomy",label:"Danh mục",code:"02"},{id:"banners",label:"Banner",code:"03"},{id:"partners",label:"Đối tác",code:"04"}];
const blankItem = { slug:"", title:"", description:"", coverUrl:"", coverAlt:"", coverWidth:1200, coverHeight:900, coverAssetId:"", categoryId:"", themeId:"", designTypeId:"", status:"DRAFT", featured:false, sortOrder:0 };
function taxonomySlug(value:string){return value.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[đĐ]/g,"d").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}

export default function AdminPage() {
  const router = useRouter(); const [user,setUser]=useState<AdminUser|null>(null); const [tab,setTab]=useState<Tab>("overview"); const [summary,setSummary]=useState<AdminSummary|null>(null); const [data,setData]=useState<Row[]>([]); const [taxonomy,setTaxonomy]=useState<Row>({categories:[],themes:[],designTypes:[]}); const [bannerRows,setBannerRows]=useState<Row[]>([]); const [busy,setBusy]=useState(true); const [error,setError]=useState(""); const [notice,setNotice]=useState(""); const [editing,setEditing]=useState<Row|null>(null); const [editingTaxonomy,setEditingTaxonomy]=useState<Row|null>(null); const [editingPartner,setEditingPartner]=useState<Row|null>(null); const [uploading,setUploading]=useState(false); const [bannerBusyKind,setBannerBusyKind]=useState<string|null>(null); const [previewItem,setPreviewItem]=useState<Row|null>(null); const [uploadRows,setUploadRows]=useState<UploadRow[]>([]); const [dropActive,setDropActive]=useState(false); const [manualSlug,setManualSlug]=useState(false); const [taxonomyDraftNames,setTaxonomyDraftNames]=useState<Record<string,string>>({}); const [regenerateTaxonomySlugId,setRegenerateTaxonomySlugId]=useState<string|null>(null); const [selectedTopicId,setSelectedTopicId]=useState("");
  const apiPaths: Partial<Record<Tab,string>>={portfolio:"/admin/portfolio",partners:"/admin/partners"}; const apiPath=apiPaths[tab]??"";
  useEffect(()=>{adminSession().then(r=>setUser(r.user)).catch(()=>router.replace("/admin/login"));},[router]);
  useEffect(()=>{if(!user)return; let active=true; setBusy(true);setError(""); Promise.all([adminRequest<{data:AdminSummary}>("/admin/dashboard"),adminRequest<{data:Row}>("/admin/taxonomy"),adminRequest<{data:Row[]}>("/admin/banners")]).then(([s,t,b])=>{if(!active)return;setSummary(s.data);setTaxonomy(t.data);setBannerRows(b.data);}).catch(e=>active&&setError(e.message)).finally(()=>active&&setBusy(false)); return ()=>{active=false};},[user,tab]);
  useEffect(()=>{if(!user||!apiPath)return;adminRequest<{data:Row[]}>(apiPath).then(r=>setData(r.data)).catch(e=>setError(e.message));},[user,apiPath]);
  useEffect(()=>{setSelectedTopicId(editing?.themeId??"");},[editing?.id,editing?.themeId]);
  useEffect(()=>{if(!previewItem)return;const onKey=(event:KeyboardEvent)=>{if(event.key==="Escape")setPreviewItem(null)};window.addEventListener("keydown",onKey);return()=>window.removeEventListener("keydown",onKey)},[previewItem]);
  async function uploadCover(event:React.ChangeEvent<HTMLInputElement>){const file=event.target.files?.[0];event.target.value="";if(!file||!editing)return;if(file.size>8*1024*1024){setError("Ảnh phải nhỏ hơn hoặc bằng 8 MB.");return}setUploading(true);setError("");try{const dimensions=await createImageBitmap(file).then(image=>{const size={width:image.width,height:image.height};image.close();return size}).catch(()=>({width:1200,height:900}));const form=new FormData();form.append("file",file);const result=await adminRequest<{data:Row}>("/admin/storage/upload",{method:"POST",body:form});setEditing(current=>current?{...current,coverUrl:result.data.url,coverAssetId:result.data.id,coverAsset:result.data,coverAlt:current.coverAlt||file.name,coverWidth:dimensions.width,coverHeight:dimensions.height}:current);setNotice("Ảnh đã tải lên Backend và được ghi metadata vào PostgreSQL.")}catch(e){setError(e instanceof Error?e.message:"Tải ảnh lên chưa thành công.")}finally{setUploading(false)}}
  function addFiles(files: FileList | File[]) {
    const available=Math.max(0,20-uploadRows.length);
    const selected=Array.from(files).slice(0,available);
    if(Array.from(files).length>available)setError("Mỗi tác phẩm hỗ trợ tối đa 20 ảnh.");
    selected.forEach(file => {
      const valid=/^(image\/(jpeg|png|webp))$/.test(file.type)&&file.size<=8*1024*1024;
      const key = `${file.name}-${file.size}-${file.lastModified}`;
      const rowError=file.size>8*1024*1024?"Vượt quá giới hạn 8 MB.":!valid?"Định dạng không được hỗ trợ. Chọn JPG, PNG hoặc WebP.":undefined;
      setUploadRows(current => current.some(row => row.key === key) ? current : [...current, { key, file, preview: valid?URL.createObjectURL(file):"", valid, width: 0, height: 0, progress: 0, status: valid?"queued":"error", error:rowError }]);
      if(valid)createImageBitmap(file).then(image => { const width=image.width, height=image.height; image.close(); setUploadRows(current=>current.map(row=>row.key===key?{...row,width,height}:row)); }).catch(()=>{});
    });
  }
  async function removeUpload(key: string) { const row=uploadRows.find(item=>item.key===key);if(!row)return;if(row.asset){try{await adminRequest(`/admin/storage/assets/${row.asset.id}`,{method:"DELETE"})}catch(e){setError(e instanceof Error?e.message:"Không thể gỡ file đã tải lên.");return}}URL.revokeObjectURL(row.preview);setUploadRows(current=>current.filter(item=>item.key!==key)); }
  async function uploadPending() { const pending=uploadRows.filter(row=>row.valid&&row.status!=="uploaded");let index=0;await Promise.all(Array.from({length:Math.min(3,pending.length)},async()=>{while(index<pending.length){const row=pending[index++];await uploadOne(row.key)}})); }
  async function discardNewItem() { const results=await Promise.allSettled(uploadRows.filter(row=>row.asset).map(row=>adminRequest(`/admin/storage/assets/${row.asset!.id}`,{method:"DELETE"})));uploadRows.forEach(row=>URL.revokeObjectURL(row.preview));setUploadRows([]);setEditing(null);if(results.some(result=>result.status==="rejected"))setError("Có ảnh tạm chưa gỡ được khỏi máy chủ; bạn có thể tải lại trang và thử xóa tác phẩm nháp."); }
  async function uploadOne(key: string) {
    const row=uploadRows.find(item=>item.key===key); if(!row||!row.valid||row.status==="uploading"||row.status==="uploaded")return;
    setUploadRows(current=>current.map(item=>item.key===key?{...item,status:"uploading",progress:0,error:undefined}:item));
    try { const result=await adminUploadFile(row.file,value=>setUploadRows(current=>current.map(item=>item.key===key?{...item,progress:value}:item))); setUploadRows(current=>current.map(item=>item.key===key?{...item,status:"uploaded",progress:100,width:result.data.width,height:result.data.height,asset:result.data}:item)); }
    catch(e) { setUploadRows(current=>current.map(item=>item.key===key?{...item,status:"error",error:e instanceof Error?e.message:"Tải ảnh chưa thành công."}:item)); }
  }
  async function createPortfolioSet(event:React.FormEvent<HTMLFormElement>) {
    event.preventDefault(); const form=event.currentTarget; const fd=new FormData(form); const images=uploadRows.filter(row=>row.status==="uploaded"&&row.asset);
    if(!images.length||images.length!==uploadRows.length){setError("Hãy tải lên thành công tất cả ảnh trước khi lưu tác phẩm.");return;}
    const title=String(fd.get("title")||"").trim(); const payload={slug:String(fd.get("slug")||""),title,description:String(fd.get("description")||""),coverUrl:images[0].asset!.url,coverAlt:images[0].file.name,coverWidth:images[0].width,coverHeight:images[0].height,coverAssetId:images[0].asset!.id,categoryId:String(fd.get("categoryId")),themeId:String(fd.get("themeId")),designTypeId:String(fd.get("designTypeId")),status:String(fd.get("status")),featured:fd.has("featured"),sortOrder:Number(fd.get("sortOrder")||0),images:images.map(row=>({url:row.asset!.url,alt:row.file.name,width:row.width,height:row.height}))};
    setUploading(true);setError("");try{await adminRequest("/admin/portfolio/with-images",{method:"POST",body:JSON.stringify(payload)});setEditing(null);uploadRows.forEach(row=>URL.revokeObjectURL(row.preview));setUploadRows([]);setManualSlug(false);setNotice(`${title} đã được lưu cùng ${images.length} ảnh${payload.status==="PUBLISHED"?" và xuất bản":" dưới dạng bản nháp"}.`);setData((await adminRequest<{data:Row[]}>("/admin/portfolio")).data);}catch(e){setError(e instanceof Error?e.message:"Không thể lưu tác phẩm.");}finally{setUploading(false);}
  }
  async function saveItem(event:React.FormEvent<HTMLFormElement>){event.preventDefault();const fd=new FormData(event.currentTarget);const payload:Record<string,unknown>=Object.fromEntries(fd.entries());payload.coverWidth=Number(payload.coverWidth);payload.coverHeight=Number(payload.coverHeight);payload.sortOrder=Number(payload.sortOrder);payload.featured=fd.has("featured");payload.coverAssetId=editing?.coverAssetId||undefined;try{await adminRequest(editing?.id?`/admin/portfolio/${editing.id}`:"/admin/portfolio",{method:editing?.id?"PATCH":"POST",body:JSON.stringify(payload)});setEditing(null);setNotice("Tác phẩm đã được lưu.");setData((await adminRequest<{data:Row[]}>("/admin/portfolio")).data);}catch(e){setError((e as Error).message)}}
  async function saveTaxonomy(kind:string,event:React.FormEvent<HTMLFormElement>){event.preventDefault();const fd=new FormData(event.currentTarget);const payload:Record<string,unknown>={name:String(fd.get("name")||""),sortOrder:Number(fd.get("sortOrder")||0)};if(kind==="categories")payload.themeId=String(fd.get("themeId")||"");if(kind==="themes")payload.showOnHome=fd.has("showOnHome");try{await adminRequest(`/admin/taxonomy/${kind}`,{method:"POST",body:JSON.stringify(payload)});setTaxonomy((await adminRequest<{data:Row}>("/admin/taxonomy")).data);setTaxonomyDraftNames(current=>({...current,[kind]:""}));setNotice("Mục phân loại đã được thêm.");}catch(e){setError((e as Error).message)}}
  async function deleteTaxonomy(kind:string,row:Row){const count=Number(row._count?.items??0);if(count>0){setError(`Không thể xóa “${row.name}” vì đang được ${count} tác phẩm sử dụng.`);return;}const childCount=kind==="themes"?Number(row._count?.categories??0):0;if(childCount>0){setError(`Chủ đề “${row.name}” đang có ${childCount} danh mục. Hãy xóa các danh mục trước; không có dữ liệu nào bị xóa dây chuyền.`);return;}if(!window.confirm(`Xóa “${row.name}”? Thao tác này không thể hoàn tác.`))return;setError("");try{await adminRequest(`/admin/taxonomy/${kind}/${row.id}`,{method:"DELETE"});setTaxonomy((await adminRequest<{data:Row}>("/admin/taxonomy")).data);setNotice(`Đã xóa ${row.name}.`);if(editingTaxonomy?.id===row.id)setEditingTaxonomy(null);}catch(e){setError((e as Error).message)}}
  async function updateTaxonomy(event:React.FormEvent<HTMLFormElement>){event.preventDefault();if(!editingTaxonomy)return;const fd=new FormData(event.currentTarget);const payload:Record<string,unknown>=Object.fromEntries(fd.entries());payload.sortOrder=Number(payload.sortOrder);payload.regenerateSlug=fd.has("regenerateSlug");if(editingTaxonomy?.kind==="themes")payload.showOnHome=fd.has("showOnHome");delete payload.slug;try{await adminRequest(`/admin/taxonomy/${editingTaxonomy.kind}/${editingTaxonomy.id}`,{method:"PATCH",body:JSON.stringify(payload)});setTaxonomy((await adminRequest<{data:Row}>("/admin/taxonomy")).data);setEditingTaxonomy(null);setRegenerateTaxonomySlugId(null);setNotice("Mục phân loại đã được cập nhật.")}catch(e){setError((e as Error).message)}}
  async function moveTaxonomy(kind:string,rows:Row[],index:number,direction:-1|1){const next=[...rows];const target=index+direction;if(target<0||target>=next.length)return;[next[index],next[target]]=[next[target],next[index]];try{await adminRequest(`/admin/taxonomy/${kind}/reorder`,{method:"PATCH",body:JSON.stringify({ids:next.map(row=>row.id)})});setTaxonomy((await adminRequest<{data:Row}>("/admin/taxonomy")).data)}catch(e){setError((e as Error).message)}}
  async function updatePartner(event:React.FormEvent<HTMLFormElement>){event.preventDefault();if(!editingPartner)return;const fd=new FormData(event.currentTarget);const payload:Record<string,unknown>=Object.fromEntries(fd.entries());payload.sortOrder=Number(payload.sortOrder);try{await adminRequest(`/admin/partners/${editingPartner.id}`,{method:"PATCH",body:JSON.stringify(payload)});setData((await adminRequest<{data:Row[]}>("/admin/partners")).data);setEditingPartner(null);setNotice("Logo đối tác đã được cập nhật.")}catch(e){setError((e as Error).message)}}
  async function savePartner(event:React.FormEvent<HTMLFormElement>){event.preventDefault();const payload=Object.fromEntries(new FormData(event.currentTarget).entries());try{await adminRequest("/admin/partners",{method:"POST",body:JSON.stringify(payload)});setData((await adminRequest<{data:Row[]}>("/admin/partners")).data);setNotice("Logo đối tác đã được lưu.");}catch(e){setError((e as Error).message)}}
  function updateBannerDraft(kind:string,field:"imageUrl"|"alt"|"isEnabled",value:string|boolean){setBannerRows(current=>current.map(row=>row.kind===kind?{...row,[field]:value}:row));}
  async function uploadBanner(kind:string,event:React.ChangeEvent<HTMLInputElement>){const file=event.currentTarget.files?.[0];event.currentTarget.value="";if(!file)return;if(!/^(image\/(jpeg|png|webp))$/.test(file.type)){setError("Chọn ảnh JPG, PNG hoặc WebP.");return}if(file.size>8*1024*1024){setError("Ảnh banner phải nhỏ hơn hoặc bằng 8 MB.");return}setBannerBusyKind(kind);setError("");setNotice("");try{const form=new FormData();form.append("file",file);const result=await adminRequest<{data:UploadedImage}>("/admin/storage/upload",{method:"POST",body:form});setBannerRows(current=>current.map(row=>row.kind===kind?{...row,imageUrl:result.data.url,alt:row.alt||file.name}:row));setNotice(`Đã tải ảnh ${kind==="TET"?"banner Tết":"banner thường ngày"} lên. Nhấn LƯU để cập nhật banner công khai.`)}catch(e){setError((e as Error).message)}finally{setBannerBusyKind(null)}}
  async function saveBanner(row:Row,event:React.FormEvent<HTMLFormElement>){event.preventDefault();const fd=new FormData(event.currentTarget);const payload={imageUrl:String(fd.get("imageUrl")??"").trim()||null,alt:String(fd.get("alt")??"").trim()||null,isEnabled:fd.has("isEnabled")};setBannerBusyKind(row.kind);setError("");setNotice("");try{const saved=await adminRequest<{data:Row}>(`/admin/banners/${row.kind}`,{method:"PATCH",body:JSON.stringify(payload)});setBannerRows(current=>current.map(item=>item.kind===row.kind?saved.data:item));setNotice(`${row.kind==="TET"?"Banner Tết":"Banner thường ngày"} đã được lưu.`);try{const refreshed=await adminRequest<{data:Row[]}>("/admin/banners");setBannerRows(refreshed.data)}catch{setNotice(`${row.kind==="TET"?"Banner Tết":"Banner thường ngày"} đã lưu; danh sách chưa làm mới được.`)}}catch(e){setError((e as Error).message)}finally{setBannerBusyKind(null)}}
  async function deleteItem(row:Row){if(!window.confirm(`Xóa vĩnh viễn “${row.title}” và ảnh bìa đã tải lên? Thao tác này không thể hoàn tác.`))return;try{await adminRequest(`/admin/portfolio/${row.id}`,{method:"DELETE"});setData(current=>current.filter(item=>item.id!==row.id));setNotice("Tác phẩm đã được xóa.")}catch(e){setError((e as Error).message)}}
  async function archive(row:Row){if(!window.confirm(`Ẩn “${row.title}” khỏi danh sách đang quản lý? Bản ghi sẽ được lưu trữ.`))return;try{await adminRequest(`/admin/portfolio/${row.id}/archive`,{method:"POST",body:"{}"});setData(data.filter(x=>x.id!==row.id));setNotice("Tác phẩm đã được lưu trữ.");}catch(e){setError((e as Error).message)}}
  async function logout(){try{await adminLogout()}finally{router.replace("/admin/login")}}
  if(!user)return <main className={styles.loading}>ĐANG MỞ BÀN LÀM VIỆC…</main>;
  const metrics=[ ["TÁC PHẨM",summary?.total??"—"],["ĐANG XUẤT BẢN",summary?.published??"—"],["LƯỢT XEM",summary?.views??"—"],["DANH MỤC",summary?.categories??"—"] ];
  return <main className={styles.shell}><aside className={styles.rail}><a className={styles.brand} href="/admin">JUNX <span>DESIGN</span><small>CONTENT OFFICE</small></a><p className={styles.railLabel}>WORKSPACE</p><nav>{tabs.map(item=><button key={item.id} className={`${styles.navItem} ${tab===item.id?styles.navActive:""}`} onClick={()=>{setTab(item.id);setEditing(null);setNotice("")}}><span>{item.code}</span>{item.label}</button>)}</nav><div className={styles.railBottom}><span className={styles.liveDot}/> DATABASE / POSTGRESQL<br/>SESSION / PROTECTED</div></aside>
    <section className={styles.main}><header className={styles.topbar}><span>JUNX / ADMINISTRATION / {tabs.find(x=>x.id===tab)?.label.toUpperCase()}</span><div><span>{user.email}</span><button onClick={logout}>KẾT THÚC PHIÊN ↗</button></div></header><div className={styles.content}><div className={styles.heading}><div><p className={styles.eyebrow}>BÀN LÀM VIỆC NỘI BỘ · 12.10.2026</p><h1>{tab==="overview"?<>Một góc nhìn<br/><em>toàn cảnh.</em></>:tabs.find(x=>x.id===tab)?.label}</h1><p className={styles.subhead}>Quản lý nội dung JUNX DESIGN, đồng bộ trực tiếp với cơ sở dữ liệu.</p></div><span className={styles.index}>JX—{tabs.find(x=>x.id===tab)?.code}</span></div>
      {notice&&<p className={styles.notice} role="status">{notice}</p>}{error&&<p className={styles.error} role="alert">{error}</p>}{busy&&<p className={styles.muted}>Đang đồng bộ dữ liệu…</p>}
      {tab==="overview"&&<><div className={styles.metrics}>{metrics.map(([label,value])=><article key={label}><span>{label}</span><strong>{value}</strong><small>LIVE FROM POSTGRESQL</small></article>)}</div><div className={styles.overviewGrid}><section className={styles.panel}><div className={styles.panelHead}><h2>VỪA CẬP NHẬT</h2><button onClick={()=>setTab("portfolio")}>MỞ THƯ VIỆN ↗</button></div>{summary?.recent.length?summary.recent.map(row=><div className={styles.recent} key={row.id}><span>{row.title}</span><small>{row.status} · {new Date(row.updatedAt).toLocaleDateString("vi-VN")}</small></div>):<p className={styles.empty}>Chưa có tác phẩm trong hệ thống.</p>}</section><section className={styles.panel}><div className={styles.panelHead}><h2>HỆ THỐNG</h2><span className={styles.liveBadge}>● ĐANG KẾT NỐI</span></div><p className={styles.systemText}>Danh mục đang hoạt động <b>{summary?.categories??"—"}</b></p><p className={styles.systemText}>Logo đối tác <b>{summary?.partners??"—"}</b></p><p className={styles.systemText}>Banner cấu hình <b>{summary?.banners??"—"}</b></p><p className={styles.storageNote}>LƯU TRỮ ẢNH · LOCAL FILE STORAGE CHỈ DÙNG TRONG DEVELOPMENT</p></section></div></>}
      {tab==="portfolio"&&<><div className={styles.sectionToolbar}><h2>THƯ VIỆN TÁC PHẨM <span>{data.length.toString().padStart(2,"0")}</span></h2><button className={styles.primaryButton} onClick={()=>setEditing({...blankItem})}>+ THÊM TÁC PHẨM</button></div>{editing?.id&&<form key={`${editing.id??"new"}-${editing.coverAssetId??"none"}`} className={styles.editForm} onSubmit={saveItem}><h3>{editing.id?"CHỈNH SỬA TÁC PHẨM":"TÁC PHẨM MỚI"}</h3><div className={styles.uploadBox}><input className={styles.fileInput} id="portfolio-cover-upload" type="file" accept="image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp" onChange={uploadCover}/><label className={styles.primaryButton} htmlFor="portfolio-cover-upload">{uploading?"ĐANG TẢI…":"TẢI ẢNH LÊN"}</label><span>JPG · PNG · WEBP · TỐI ĐA 8 MB</span>{editing.coverUrl&&<img src={editing.coverUrl} alt={editing.coverAlt||"Xem trước ảnh bìa"} className={styles.uploadPreview}/>}</div><div className={styles.formGrid}>{[["title","Tên tác phẩm"],["slug","Slug"],["coverWidth","Chiều rộng"],["coverHeight","Chiều cao"],["sortOrder","Thứ tự hiển thị"]].map(([name,label])=><label key={name}>{label}<input name={name} type="number" min="1" defaultValue={editing[name]??""} required/></label>)}<label>URL ảnh bìa<input name="coverUrl" value={editing.coverUrl??""} onChange={e=>setEditing(current=>current?{...current,coverUrl:e.target.value,coverAssetId:e.target.value===current.coverAsset?.url?current.coverAssetId:""}:current)} required/></label><label>Mô tả ảnh<input name="coverAlt" value={editing.coverAlt??""} onChange={e=>setEditing(current=>current?{...current,coverAlt:e.target.value}:current)} required/></label><label>Mô tả<input name="description" defaultValue={editing.description??""}/></label><label>Trạng thái<select name="status" defaultValue={editing.status??"DRAFT"}><option value="DRAFT">Bản nháp</option><option value="PUBLISHED">Xuất bản</option></select></label><label>Chủ đề<select required name="themeId" value={selectedTopicId} onChange={event=>{const themeId=event.target.value;setSelectedTopicId(themeId);setEditing(current=>current?{...current,themeId,categoryId:""}:current)}}><option value="">Chọn chủ đề…</option>{taxonomy.themes.map((x:Row)=><option key={x.id} value={x.id}>{x.name}</option>)}</select></label><label>Danh mục<select required name="categoryId" value={editing.categoryId??""} onChange={event=>setEditing(current=>current?{...current,categoryId:event.target.value}:current)} disabled={!selectedTopicId}><option value="">Chọn danh mục…</option>{taxonomy.categories.filter((x:Row)=>x.themeId===selectedTopicId).map((x:Row)=><option key={x.id} value={x.id}>{x.name}</option>)}</select></label><label>Loại thiết kế<select required name="designTypeId" defaultValue={editing.designTypeId??""}><option value="">Chọn…</option>{taxonomy.designTypes.map((x:Row)=><option key={x.id} value={x.id}>{x.name}</option>)}</select></label><label className={styles.checkLabel}><input type="checkbox" name="featured" defaultChecked={!!editing.featured}/> Nổi bật</label></div><div className={styles.formActions}><button type="button" onClick={()=>setEditing(null)}>HỦY</button><button className={styles.primaryButton}>LƯU TÁC PHẨM ↗</button></div></form>}{editing&&!editing.id&&<form className={styles.editForm} onSubmit={createPortfolioSet}><h3>TÁC PHẨM MỚI · BỘ ẢNH</h3><div className={styles.dropZone+" "+(dropActive?styles.dropActive:"")} onDragOver={event=>{event.preventDefault();setDropActive(true)}} onDragLeave={()=>setDropActive(false)} onDrop={event=>{event.preventDefault();setDropActive(false);addFiles(event.dataTransfer.files)}}><input className={styles.fileInput} id="portfolio-multi-upload" type="file" multiple accept="image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp" onChange={event=>{if(event.target.files)addFiles(event.target.files);event.target.value=""}}/><label htmlFor="portfolio-multi-upload"><strong>KÉO THẢ ẢNH VÀO ĐÂY</strong><span>hoặc chọn nhiều ảnh từ máy</span></label><small>JPG · PNG · WEBP · TỐI ĐA 8 MB / ẢNH · TỐI ĐA 20 ẢNH</small></div>{uploadRows.length>0&&<div className={styles.uploadList}><div className={styles.uploadListHead}><b>{uploadRows.length} ẢNH ĐÃ CHỌN</b><button type="button" onClick={()=>uploadPending()}>TẢI ẢNH CHƯA TẢI LÊN ↗</button></div>{uploadRows.map((row,index)=><article className={styles.uploadRow} key={row.key}>{row.preview?<button type="button" className={styles.thumbButton} onClick={()=>setPreviewItem({title:row.file.name,coverUrl:row.preview,coverAlt:row.file.name,coverWidth:row.width,coverHeight:row.height,status:row.status})}><img src={row.preview} alt=""/></button>:<div className={styles.uploadInvalid}>!</div>}<div className={styles.uploadMeta}><b>{row.file.name}</b><span>{row.width&&row.height?row.width+" × "+row.height+" px · ":"Đang đọc kích thước · "}{(row.file.size/1024/1024).toFixed(2)} MB{index===0?" · ẢNH BÌA":""}</span>{row.status==="uploading"&&<progress max="100" value={row.progress}/ >}{row.status==="uploaded"&&<small className={styles.uploadSuccess}>ĐÃ TẢI LÊN · {row.progress}%</small>}{row.error&&<small className={styles.uploadError}>{row.error}</small>}</div><div className={styles.uploadActions}>{row.valid&&row.status!=="uploaded"&&<button type="button" onClick={()=>uploadOne(row.key)}>{row.status==="uploading"?row.progress+"%":row.status==="error"?"THỬ LẠI":"TẢI LÊN"}</button>}<button type="button" onClick={()=>removeUpload(row.key)}>BỎ</button></div></article>)}</div>}<div className={styles.formGrid}><label>Tên tác phẩm<input name="title" required onChange={event=>{if(manualSlug)return;const slug=event.target.value.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[đĐ]/g,"d").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");const input=event.currentTarget.form?.elements.namedItem("slug") as HTMLInputElement|null;if(input)input.value=slug}}/></label><label>Slug<input name="slug" required onChange={event=>{setManualSlug(true);event.currentTarget.value=event.currentTarget.value.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-")}} placeholder="tu-dong-tao-tu-ten"/></label><label>Mô tả<input name="description"/></label><label>Trạng thái<select name="status"><option value="DRAFT">Bản nháp</option><option value="PUBLISHED">Xuất bản ngay</option></select></label><label>Chủ đề<select required name="themeId" value={selectedTopicId} onChange={event=>{const themeId=event.target.value;setSelectedTopicId(themeId);setEditing(current=>current?{...current,themeId,categoryId:""}:current)}}><option value="">Chọn chủ đề trước…</option>{taxonomy.themes.map((x:Row)=><option key={x.id} value={x.id}>{x.name}</option>)}</select></label><label>Danh mục<select required name="categoryId" value={editing.categoryId??""} onChange={event=>setEditing(current=>current?{...current,categoryId:event.target.value}:current)} disabled={!selectedTopicId}><option value="">Chọn danh mục…</option>{taxonomy.categories.filter((x:Row)=>x.themeId===selectedTopicId).map((x:Row)=><option key={x.id} value={x.id}>{x.name}</option>)}</select></label><label>Loại thiết kế<select required name="designTypeId"><option value="">Chọn…</option>{taxonomy.designTypes.map((x:Row)=><option key={x.id} value={x.id}>{x.name}</option>)}</select></label><label>Thứ tự hiển thị<input name="sortOrder" type="number" min="0" defaultValue="0"/></label><label className={styles.checkLabel}><input type="checkbox" name="featured"/> Nổi bật</label></div><div className={styles.formActions}><button type="button" onClick={discardNewItem}>HỦY</button><button className={styles.primaryButton} disabled={uploading||!uploadRows.length||uploadRows.some(row=>row.status!=="uploaded")}>{uploading?"ĐANG LƯU…":"LƯU "+uploadRows.length+" ẢNH ↗"}</button></div></form>}<div className={styles.tableWrap}><table><thead><tr><th>TÁC PHẨM</th><th>PHÂN LOẠI</th><th>TRẠNG THÁI</th><th>THỨ TỰ</th><th>THAO TÁC</th></tr></thead><tbody>{data.map(row=><tr key={row.id}><td><b>{row.title}</b><small>/{row.slug}</small></td><td>{row.category?.name??"—"}<small>{row.theme?.name} · {row.designType?.name}</small></td><td><span className={styles.status}>{row.status}</span></td><td>{row.sortOrder}</td><td><button onClick={()=>setPreviewItem(row)}>XEM</button><button onClick={()=>setEditing(row)}>SỬA</button><button onClick={()=>archive(row)}>ẨN</button><button onClick={()=>deleteItem(row)}>XÓA</button></td></tr>)}</tbody></table>{!data.length&&<p className={styles.empty}>Chưa có tác phẩm. Có thể tạo mới tại đây.</p>}</div><div className={styles.storageNote}>ẢNH ĐƯỢC LƯU CỤC BỘ TRONG BACKEND/UPLOADS · DEVELOPMENT ONLY</div></>}
      {tab==="taxonomy"&&<div className={styles.taxonomyGrid}>{[["categories","Danh mục"],["themes","Chủ đề"],["designTypes","Loại thiết kế"]].map(([key,label])=><section className={styles.panel} key={key}><div className={styles.panelHead}><h2>{label.toUpperCase()}</h2></div><form className={`${styles.inlineForm} ${key==="categories"?styles.taxonomyCreateForm:""}`} onSubmit={e=>saveTaxonomy(key,e)}>{key==="categories"&&<select name="themeId" required defaultValue=""><option value="" disabled>Thuộc chủ đề…</option>{taxonomy.themes.map((topic:Row)=><option key={topic.id} value={topic.id}>{topic.name}</option>)}</select>}<input name="name" placeholder="Tên mới" value={taxonomyDraftNames[key]??""} onChange={event=>setTaxonomyDraftNames(current=>({...current,[key]:event.target.value}))} required/><input aria-label="Slug tự động" placeholder="slug tự động" value={taxonomySlug(taxonomyDraftNames[key]??"")} readOnly/><input name="sortOrder" type="number" min="0" placeholder="Thứ tự"/>{key==="themes"&&<label className={styles.checkLabel}><input type="checkbox" name="showOnHome"/> Hiển thị trang chủ</label>}<button type="submit" aria-label={`Thêm ${label}`}>+</button></form>{(taxonomy[key]??[]).map((row:Row,index:number)=><div key={row.id}><div className={styles.taxonomyRow}><span>{row.name}<small>/{row.slug} · thứ tự {row.sortOrder}</small></span><div>{key==="themes"&&<><button type="button" disabled={index===0} aria-label="Chuyển chủ đề lên" onClick={()=>moveTaxonomy(key,taxonomy[key],index,-1)}>↑</button><button type="button" disabled={index===taxonomy[key].length-1} aria-label="Chuyển chủ đề xuống" onClick={()=>moveTaxonomy(key,taxonomy[key],index,1)}>↓</button><button type="button" onClick={async()=>{await adminRequest(`/admin/taxonomy/${key}/${row.id}`,{method:"PATCH",body:JSON.stringify({showOnHome:!row.showOnHome})});setTaxonomy((await adminRequest<{data:Row}>("/admin/taxonomy")).data)}}>{row.showOnHome?"HIỆN TRANG CHỦ":"ẨN TRANG CHỦ"}</button></>}<button type="button" onClick={()=>{setEditingTaxonomy({...row,kind:key});setRegenerateTaxonomySlugId(null)}}>SỬA</button><button type="button" onClick={async()=>{await adminRequest(`/admin/taxonomy/${key}/${row.id}`,{method:"PATCH",body:JSON.stringify({isActive:!row.isActive})});setTaxonomy((await adminRequest<{data:Row}>("/admin/taxonomy")).data)}}>{row.isActive?"ĐANG DÙNG":"ĐÃ ẨN"}</button><button type="button" className={styles.deleteTaxonomy} onClick={()=>deleteTaxonomy(key,row)}>XÓA</button></div></div>{editingTaxonomy?.id===row.id&&<form className={styles.editForm} onSubmit={updateTaxonomy}><label>Tên<input name="name" defaultValue={row.name} onChange={event=>setEditingTaxonomy(current=>current?.id===row.id?{...current,draftName:event.target.value}:current)} required/></label><label>Slug<input aria-label="Slug hiện tại" value={regenerateTaxonomySlugId===row.id?taxonomySlug(editingTaxonomy?.draftName??row.name):row.slug} readOnly/></label>{editingTaxonomy?.kind==="categories"&&<label>Chủ đề<select name="themeId" defaultValue={row.themeId??""} required disabled={(row._count?.items??0)>0}><option value="">Chọn chủ đề…</option>{taxonomy.themes.map((topic:Row)=><option key={topic.id} value={topic.id}>{topic.name}</option>)}</select>{(row._count?.items??0)>0&&<small>Danh mục đang có tác phẩm nên không thể chuyển Chủ đề.</small>}</label>}{editingTaxonomy?.kind==="themes"&&<label className={styles.checkLabel}><input type="checkbox" name="showOnHome" defaultChecked={!!row.showOnHome}/> Hiển thị Chủ đề trên trang chủ</label>}<label className={styles.checkLabel}><input type="checkbox" name="regenerateSlug" checked={regenerateTaxonomySlugId===row.id} onChange={event=>setRegenerateTaxonomySlugId(event.target.checked?row.id:null)}/> Xác nhận cập nhật slug theo tên</label><label>Thứ tự<input name="sortOrder" type="number" min="0" defaultValue={row.sortOrder}/></label><div className={styles.formActions}><button type="button" onClick={()=>{setEditingTaxonomy(null);setRegenerateTaxonomySlugId(null)}}>HỦY</button><button className={styles.primaryButton}>LƯU</button></div></form>}</div>)}</section>)}</div>}
      {tab==="banners"&&<div className={styles.bannerGrid}>{bannerRows.map(row=><form className={`${styles.panel} ${styles.bannerForm}`} key={row.kind} onSubmit={e=>saveBanner(row,e)}><div className={styles.bannerTitle}><div><p className={styles.eyebrow}>BANNER / {row.kind==="TET"?"CHỦ ĐỀ TẾT":"THƯỜNG NGÀY"}</p><h2>{row.kind==="TET"?"Tết":"Thường ngày"}</h2></div><span className={row.isEnabled?styles.bannerEnabled:styles.bannerDisabled}>{row.isEnabled?"ĐANG BẬT":"ĐANG TẮT"}</span></div><div className={styles.bannerPreview}>{row.imageUrl?<img src={row.imageUrl} alt={row.alt||`Xem trước banner ${row.kind==="TET"?"Tết":"thường ngày"}`}/>:<div className={styles.bannerPreviewEmpty}><span aria-hidden="true">✳</span><p>Chưa có ảnh banner</p></div>}</div><label>URL ảnh<input name="imageUrl" type="url" value={row.imageUrl??""} onChange={event=>updateBannerDraft(row.kind,"imageUrl",event.currentTarget.value)} placeholder="Dán URL ảnh hoặc tải ảnh từ máy"/></label><label>Văn bản thay thế<input name="alt" value={row.alt??""} onChange={event=>updateBannerDraft(row.kind,"alt",event.currentTarget.value)} placeholder="Mô tả ngắn cho ảnh"/></label><label className={styles.checkLabel}><input type="checkbox" name="isEnabled" checked={!!row.isEnabled} onChange={event=>updateBannerDraft(row.kind,"isEnabled",event.currentTarget.checked)}/>{row.kind==="TET"?"Bật banner và chủ đề Tết":"Bật banner thường ngày"}</label><input className={styles.fileInput} id={`banner-upload-${row.kind}`} type="file" accept="image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp" onChange={event=>uploadBanner(row.kind,event)} disabled={bannerBusyKind===row.kind}/><div className={styles.bannerActions}><label className={styles.bannerUploadButton} htmlFor={`banner-upload-${row.kind}`} aria-disabled={bannerBusyKind===row.kind}>{bannerBusyKind===row.kind?"ĐANG TẢI…":"TẢI ẢNH LÊN"}</label><button className={styles.primaryButton} type="submit" disabled={bannerBusyKind===row.kind}>{bannerBusyKind===row.kind?"ĐANG LƯU…":"LƯU THAY ĐỔI ↗"}</button></div><small className={styles.bannerHint}>JPG · PNG · WEBP · TỐI ĐA 8 MB · ẢNH LƯU LOCAL CHỈ DÙNG KHI DEVELOPMENT</small></form>)}</div>}
      {tab==="partners"&&<><section className={styles.panel}><div className={styles.panelHead}><h2>LOGO ĐỐI TÁC</h2><span>{data.length} ĐÃ GHI NHẬN</span></div><form className={styles.inlineForm} onSubmit={savePartner}><input name="name" placeholder="Tên đối tác" required/><input name="imageUrl" placeholder="URL logo" required/><input name="alt" placeholder="Alt text" required/><input name="sortOrder" type="number" min="0" placeholder="Thứ tự"/><button>THÊM ↗</button></form>{data.map(row=><div key={row.id}><div className={styles.partnerRow}><div><b>{row.name}</b><small>{row.imageUrl} · thứ tự {row.sortOrder}</small></div><div><button onClick={()=>setEditingPartner(row)}>SỬA</button><button onClick={async()=>{await adminRequest(`/admin/partners/${row.id}`,{method:"PATCH",body:JSON.stringify({isActive:!row.isActive})});setData((await adminRequest<{data:Row[]}>("/admin/partners")).data)}}>{row.isActive?"ĐANG HIỆN":"ĐÃ ẨN"}</button></div></div>{editingPartner?.id===row.id&&<form className={styles.editForm} onSubmit={updatePartner}><div className={styles.formGrid}><label>Tên<input name="name" defaultValue={row.name} required/></label><label>URL logo<input name="imageUrl" defaultValue={row.imageUrl} required/></label><label>Alt text<input name="alt" defaultValue={row.alt} required/></label><label>Thứ tự<input name="sortOrder" type="number" min="0" defaultValue={row.sortOrder}/></label></div><div className={styles.formActions}><button type="button" onClick={()=>setEditingPartner(null)}>HỦY</button><button className={styles.primaryButton}>LƯU</button></div></form>}</div>)}{!data.length&&<p className={styles.empty}>Chưa có logo đối tác.</p>}</section><p className={styles.storageNote}>UPLOAD LOGO · CHƯA CẤU HÌNH STORAGE PROVIDER. QUẢN LÝ URL LOGO ĐÃ CÓ.</p></>}
      {previewItem&&<div className={styles.previewBackdrop} role="presentation" onMouseDown={event=>{if(event.target===event.currentTarget)setPreviewItem(null)}}><section className={styles.previewDialog} role="dialog" aria-modal="true" aria-label={`Xem trước ${previewItem.title}`}><div className={styles.previewHeader}><b>{previewItem.title}</b><button type="button" onClick={()=>setPreviewItem(null)} aria-label="Đóng xem trước">ĐÓNG ×</button></div><img src={previewItem.coverUrl} alt={previewItem.coverAlt} /><p>{previewItem.coverWidth} × {previewItem.coverHeight} px · {previewItem.status}</p></section></div>}<footer className={styles.footer}>JUNX DESIGN · PRIVATE CONTENT WORKSPACE <span>BUILT FOR THE DETAILS / 2026</span></footer></div></section></main>;
}
