import {z} from "zod";
import {quoteSchema} from "./quote-schema";
import {openingSchema,validateArchitecture} from "./architecture";
import {dimensionSchema} from "./dimensions";
import {backgroundSchema} from './background';
import {boardSize,boards,inBoard} from "./board-size";
import {moduleTypes,validateBoard} from "./board";
import {circuitSizingSchema,planSizingSchema,pruneSizing} from './sizing-schema';
const id=z.string().min(1).max(80),name=z.string().trim().min(1).max(120),n=z.number().finite().min(0).max(2000);
const point=z.object({x:n,y:n});
export const kinds=["socket","double","switch1","switch2","switch5","switch6","switch7","rj45","phone","light","box","panel"] as const;
export type Kind=typeof kinds[number];
export const labels:Record<Kind,string>={socket:"Dugalj",double:"Kettős dugalj",switch1:"Egypólusú kapcsoló",switch2:"Kétpólusú kapcsoló",switch5:"Csillárkapcsoló",switch6:"Váltókapcsoló",switch7:"Keresztkapcsoló",rj45:"RJ45 adatcsatlakozó",phone:"Telefonaljzat",light:"Lámpakiállás",box:"Kötődoboz",panel:"Lakáselosztó"};
const room=z.object({id,name,x:n,y:n,w:z.number().min(8).max(1800),h:z.number().min(8).max(1800),thickness:z.number().finite().min(5).max(100).optional(),openings:z.array(openingSchema).max(50).optional()});
const wall=z.object({id,a:point,b:point,thickness:z.number().finite().min(5).max(100).optional(),openings:z.array(openingSchema).max(50).optional()});
const device=z.object({id,name,board:z.string().max(80).optional(),kind:z.enum(kinds),x:n,y:n,angle:z.number().finite(),height:z.number().min(0).max(1000),circuit:z.string().max(80)});
const route=z.object({id,name,points:z.array(point).min(2).max(300),mode:z.enum(["inside","outside"]),circuit:z.string().max(80),cable:z.string().max(60),startId:z.string().max(80).optional(),endId:z.string().max(80).optional(),planeHeight:z.number().finite().min(0).max(1000).optional(),startHeight:z.number().finite().min(0).max(1000).optional(),endHeight:z.number().finite().min(0).max(1000).optional()});
export const floorSchema=z.object({id,name,elevation:z.number().min(-30).max(100),rooms:z.array(room).max(200),walls:z.array(wall).max(1000),devices:z.array(device).max(2000),routes:z.array(route).max(2000),background:backgroundSchema.optional(),dimensions:z.array(dimensionSchema).max(500).optional()});
const floor=floorSchema;
const boardDimensions=z.object({rows:z.number().int().min(1).max(12),modulesPerRow:z.number().int().min(1).max(36)});
const building=z.object({id,name,x:n,y:n,w:z.number().min(1).max(100),h:z.number().min(1).max(100),floors:z.array(floor).max(30),board:boardDimensions.optional(),boardName:name.optional(),extraBoards:z.array(boardDimensions.extend({id,name})).max(19).optional()});
const circuit=z.object({id,name,building:id,board:z.string().max(80).optional(),phase:z.enum(["L1","L2","L3","3P"]),rating:z.number().int().min(1).max(125),curve:z.enum(["B","C","D"]),cable:z.string().max(60),rcd:z.string().max(80),load:z.number().finite().min(0).max(200000).optional(),conductorNames:z.object({L:name.optional(),L1:name.optional(),L2:name.optional(),L3:name.optional(),N:name.optional(),PE:name.optional()}).optional(),sizing:circuitSizingSchema.optional()});
const moduleSchema=z.object({id,name,building:id,board:z.string().max(80).optional(),type:z.enum(moduleTypes),width:z.number().int().min(1).max(8),row:z.number().int().min(0).max(11),slot:z.number().int().min(0).max(35),circuit:z.string().max(80)});
export const siteKinds=["supply","meter","main","panel","sub"] as const;
export const siteLabels={supply:"Bekötési pont",meter:"Villanyóra",main:"Főelosztószekrény",panel:"Lakáselosztó",sub:"Alelosztó"};
const siteNode=z.object({id,name,kind:z.enum(siteKinds),x:n,y:n,height:z.number().finite().min(-30).max(110),deviceId:z.string().max(80).optional()});
const siteRoute=z.object({id,name,from:id,to:id,via:z.array(point).max(300),level:z.number().finite().min(-30).max(100),mode:z.enum(["underground","surface","overhead"]),cable:z.string().max(80)});
const endpoint=z.object({kind:z.enum(["circuit","module"]),id,port:z.string().min(1).max(30)});
const boardWire=z.object({id,name,building:id,from:endpoint,to:endpoint});
export const planSchema=z.object({version:z.literal(1),name,quote:quoteSchema.optional(),sizing:planSizingSchema.optional(),plot:z.object({name,w:z.number().min(5).max(100),h:z.number().min(5).max(100),nodes:z.array(siteNode).max(300).default([]),routes:z.array(siteRoute).max(1000).default([])}),buildings:z.array(building).max(30),circuits:z.array(circuit).max(300),modules:z.array(moduleSchema).max(300),boardWires:z.array(boardWire).max(3000).default([])});
export type Plan=z.infer<typeof planSchema>;export type Floor=Plan["buildings"][number]["floors"][number];export type Point=z.infer<typeof point>;export type Device=z.infer<typeof device>;
export const uid=()=>crypto.randomUUID();
export function newFloor(name:string,elevation:number):Floor{return {id:uid(),name,elevation,rooms:[],walls:[],devices:[],routes:[]}}
export function nearestWall(p:Point,f:Floor):Point{const segments=[...f.walls.map(w=>[w.a,w.b]),...f.rooms.flatMap(r=>[[{x:r.x,y:r.y},{x:r.x+r.w,y:r.y}],[{x:r.x,y:r.y},{x:r.x,y:r.y+r.h}],[{x:r.x+r.w,y:r.y},{x:r.x+r.w,y:r.y+r.h}],[{x:r.x,y:r.y+r.h},{x:r.x+r.w,y:r.y+r.h}]])];let best=p,dist=20;for(const [a,b] of segments){const dx=b.x-a.x,dy=b.y-a.y,t=Math.max(0,Math.min(1,((p.x-a.x)*dx+(p.y-a.y)*dy)/(dx*dx+dy*dy||1)));const q={x:a.x+t*dx,y:a.y+t*dy},d=Math.hypot(p.x-q.x,p.y-q.y);if(d<dist){best=q;dist=d}}return best}
export function routeLength(points:Point[]){return points.slice(1).reduce((s,p,i)=>s+Math.hypot(p.x-points[i].x,p.y-points[i].y)/40,0)}
export const seed:Plan=planSchema.parse({version:1,name:"Családi ház – villamos terv",plot:{name:"Saját telek",w:40,h:30},buildings:[{id:"house",name:"Családi ház",x:5,y:5,w:15,h:10.5,floors:[{id:"ground",name:"Földszint",elevation:0,rooms:[{id:"living",name:"Nappali + étkező",x:180,y:140,w:320,h:400},{id:"bed",name:"Hálószoba",x:500,y:140,w:260,h:220},{id:"kitchen",name:"Konyha",x:500,y:360,w:260,h:180}],walls:[],devices:[{id:"d1",name:"D-01",kind:"double",x:180,y:260,angle:0,height:30,circuit:"c1"},{id:"d2",name:"D-02",kind:"socket",x:320,y:140,angle:0,height:30,circuit:"c1"},{id:"d3",name:"D-03",kind:"double",x:640,y:140,angle:0,height:30,circuit:"c2"},{id:"s1",name:"K-01",kind:"switch6",x:500,y:460,angle:0,height:110,circuit:"c3"},{id:"net",name:"A-01",kind:"rj45",x:180,y:400,angle:0,height:30,circuit:""},{id:"l1",name:"L-01",kind:"light",x:340,y:320,angle:0,height:260,circuit:"c3"},{id:"j1",name:"KD-01",kind:"box",x:500,y:200,angle:0,height:230,circuit:"c1"},{id:"p1",name:"E-01",kind:"panel",x:500,y:500,angle:0,height:150,circuit:""}],routes:[{id:"r1",name:"Nappali dugaljak",points:[{x:500,y:500},{x:500,y:140},{x:180,y:140},{x:180,y:260}],mode:"inside",circuit:"c1",cable:"3 × 2,5 mm²"},{id:"r2",name:"Világítás",points:[{x:500,y:460},{x:500,y:320},{x:340,y:320}],mode:"outside",circuit:"c3",cable:"3 × 1,5 mm²"}]},{id:"upper",name:"Emelet",elevation:3,rooms:[{id:"up1",name:"Dolgozószoba",x:180,y:140,w:320,h:220},{id:"up2",name:"Vendégszoba",x:500,y:140,w:260,h:220}],walls:[],devices:[],routes:[]}]},{id:"garage",name:"Garázs",x:25,y:6,w:7,h:6,floors:[{id:"garagefloor",name:"Földszint",elevation:0,rooms:[{id:"g1",name:"Garázs",x:200,y:180,w:280,h:240}],walls:[],devices:[],routes:[]}]}],circuits:[{id:"c1",name:"Nappali dugaljak",building:"house",phase:"L1",rating:16,curve:"B",cable:"3 × 2,5 mm²",rcd:"FI-01"},{id:"c2",name:"Hálószoba dugaljak",building:"house",phase:"L2",rating:16,curve:"B",cable:"3 × 2,5 mm²",rcd:"FI-01"},{id:"c3",name:"Világítás",building:"house",phase:"L3",rating:10,curve:"B",cable:"3 × 1,5 mm²",rcd:"FI-01"}],modules:[{id:"m0",name:"Főkapcsoló",building:"house",type:"MAIN",width:4,row:0,slot:0,circuit:""},{id:"m1",name:"FI-01 · 40 A / 30 mA · A",building:"house",type:"RCD",width:4,row:0,slot:4,circuit:""},{id:"m2",name:"Q1",building:"house",type:"MCB",width:1,row:0,slot:8,circuit:"c1"},{id:"m3",name:"Q2",building:"house",type:"MCB",width:1,row:0,slot:9,circuit:"c2"},{id:"m4",name:"Q3",building:"house",type:"MCB",width:1,row:0,slot:10,circuit:"c3"}]});
export function validatePlan(value:unknown){const p=planSchema.parse(value);const ids=new Set<string>();const add=(s:string)=>{if(ids.has(s))throw Error("Ismétlődő azonosító.");ids.add(s)};p.buildings.forEach(b=>{add(b.id);b.extraBoards?.forEach(v=>add(v.id));b.floors.forEach(f=>{add(f.id);[...f.rooms,...f.walls,...f.devices,...f.routes,...(f.dimensions||[])].forEach(v=>add(v.id))})});p.circuits.forEach(c=>{add(c.id);if(!p.buildings.some(b=>b.id===c.building&&boards(b).some(v=>v.id===(c.board||''))))throw Error("Hiányzó épület.")});p.modules.forEach(m=>{add(m.id);const b=p.buildings.find(b=>b.id===m.building),size=boardSize(b,m.board);if(!b||!boards(b).some(v=>v.id===(m.board||''))||m.row>=size.rows||m.slot+m.width>size.modulesPerRow)throw Error("Érvénytelen modulhely.");if(p.modules.some(x=>x.id!==m.id&&x.building===m.building&&inBoard(x,m.board)&&x.row===m.row&&x.slot<m.slot+m.width&&m.slot<x.slot+x.width))throw Error("Az elosztómodulok átfedik egymást.")});for(const b of p.buildings){for(const f of b.floors){for(const d of [...f.devices,...f.routes])if(d.circuit&&!p.circuits.some(c=>c.id===d.circuit&&c.building===b.id))throw Error("Érvénytelen áramkör.")}for(const m of p.modules.filter(m=>m.building===b.id))if(m.circuit&&!p.circuits.some(c=>c.id===m.circuit&&c.building===b.id&&inBoard(c,m.board)))throw Error("Érvénytelen moduláramkör.")}
for(const b of p.buildings)for(const f of b.floors)validateArchitecture(f,add);
for(const b of p.buildings)for(const f of b.floors)for(const d of f.devices)if(d.kind==='panel'&&!boards(b).some(v=>v.id===(d.board||'')))throw Error('Hiányzó alaprajzi elosztó.');
for(const b of p.buildings)for(const f of b.floors)for(const r of f.routes){
 for(const key of ["startId","endId"] as const){if(r[key]&&!f.devices.some(d=>d.id===r[key]))throw Error("A nyomvonal végpontja hiányzik.");if(r[key]===undefined){const end=r.points[key==="startId"?0:r.points.length-1];r[key]=f.devices.find(d=>Math.hypot(d.x-end.x,d.y-end.y)<1)?.id||"";}}
 r.planeHeight??=260;r.startHeight??=r.planeHeight;r.endHeight??=r.planeHeight;
}
for(const node of p.plot.nodes){add(node.id);if(node.deviceId&&!p.buildings.some(b=>b.floors.some(f=>f.devices.some(d=>d.id===node.deviceId))))throw Error("A telki pont hivatkozott szerelvénye hiányzik.");}
for(const r of p.plot.routes){add(r.id);if(r.from===r.to||!p.plot.nodes.some(n=>n.id===r.from)||!p.plot.nodes.some(n=>n.id===r.to))throw Error("A telki nyomvonal két különböző, létező végpontot igényel.");}
p.boardWires.forEach(w=>add(w.id));validateBoard(p);
pruneSizing(p);
return p}
