function bookId_() {
  const id = PropertiesService.getScriptProperties().getProperty('BOOK_ID');
  if (!id) throw new Error('Előbb futtasd a setupTemplate függvényt az üres táblázatból.');
  return id;
}
const ZONE = 'Europe/Budapest';
const CURRENCIES = ['HUF','EUR','RON','CZK','PLN','DKK','SEK','CHF'];
function currencyLabel_(currency) { return ({HUF:'Ft',EUR:'€'})[currency] || currency; }

// Run once in the editor, BEFORE deploying. Never deploy with public access.
function initialize() {
  const active = Session.getActiveUser().getEmail().toLowerCase();
  const effective = Session.getEffectiveUser().getEmail().toLowerCase();
  if (!active || active !== effective) throw new Error('A saját fiókodból futtasd az előkészítést.');
  const props = PropertiesService.getScriptProperties();
  const owner = props.getProperty('OWNER_EMAIL');
  if (owner && owner !== active) throw new Error('Már másik tulajdonos van beállítva.');
  workbook_();
  props.setProperty('OWNER_EMAIL', active);
  return 'Előkészítve. Közzététel: végrehajtás saját néven, hozzáférés: Csak én.';
}

function authorize_() {
  const owner = PropertiesService.getScriptProperties().getProperty('OWNER_EMAIL');
  const active = Session.getActiveUser().getEmail().toLowerCase();
  if (!owner || !active || active !== owner) throw new Error('Csak a beállított saját Google-fiókkal használható.');
}

function doGet() {
  authorize_();
  return HtmlService.createHtmlOutputFromFile('Index').setTitle('Tankolás')
    .addMetaTag('viewport', 'width=device-width, initial-scale=1');
}

function workbook_() {
  const book = SpreadsheetApp.openById(bookId_());
  const sheet = book.getSheetByName('Tankolások');
  if (!sheet || !book.getSheetByName('Listák')) throw new Error('Hiányzó munkalap.');
  const headers = sheet.getRange(1, 1, 1, 14).getValues()[0];
  const expected = {0:'Dátum',2:'Márka',3:'Hely',4:'Egységár',5:'Teljes költség',7:'Kilométer óra',8:'Megtett út',11:'Pénznem',12:'Tele tank?'};
  Object.keys(expected).forEach(i => {if(headers[i] !== expected[i]) throw new Error('A táblázat oszlopai megváltoztak. A mentés leállt.');});
  return book;
}

function history_(sheet) {
  const all = sheet.getRange(2, 1, sheet.getMaxRows()-1, 14).getValues();
  return all.map((values,i)=>({row:i+2,values})).filter(r=>r.values[0] !== '');
}

function dateText_(value) {
  if (!(value instanceof Date) || isNaN(value.getTime())) throw new Error('Hibás dátum van a táblázatban.');
  return Utilities.formatDate(value, ZONE, 'yyyy-MM-dd');
}

function fuelOptions_(sheet) {
  const rule = sheet.getRange('K2').getDataValidation();
  if (!rule || rule.getCriteriaType() !== SpreadsheetApp.DataValidationCriteria.VALUE_IN_LIST) throw new Error('Az üzemanyaglista ellenőrzést igényel.');
  return rule.getCriteriaValues()[0];
}

function getInitialData() {
  authorize_();
  const book = workbook_(), sheet = book.getSheetByName('Tankolások');
  const records = history_(sheet), last = records[records.length-1];
  const stations = [], seen = new Set();
  records.slice().reverse().forEach(r=>{
    const [brand, place] = [String(r.values[2]),String(r.values[3])];
    const key = JSON.stringify([brand,place]);
    if (brand && place && !seen.has(key)) {seen.add(key);stations.push({brand,place});}
  });
  const lists = book.getSheetByName('Listák').getRange('A2:B200').getValues();
  const now = new Date();
  return {currencies:CURRENCIES, today:Utilities.formatDate(now,ZONE,'yyyy-MM-dd'), time:Utilities.formatDate(now,ZONE,'HH:mm'), stations,
    brands:lists.map(r=>r[0]).filter(String), places:lists.map(r=>r[1]).filter(String),
    fuels:fuelOptions_(sheet), last: last ? {date:dateText_(last.values[0]),odometer:last.values[7],fuel:last.values[10]}:null};
}

function number_(value, name) {
  const text = String(value == null ? '' : value).trim().replace(/[\s\u00a0\u202f]/g,'').replace(',','.');
  if (!/^\d+(\.\d+)?$/.test(text)) throw new Error(name+': adj meg pozitív számot.');
  const n=Number(text);
  if (!Number.isFinite(n) || n <= 0) throw new Error(name+': adj meg pozitív számot.');
  return n;
}

function text_(value, name, limit) {
  const s=String(value == null ? '' : value).trim();
  if (!s || s.length>limit || /^[=+@\-]/.test(s) || /[\x00-\x1f]/.test(s)) throw new Error(name+': ellenőrizd a beírt szöveget.');
  return s;
}

function normalize_(p) {
  if (!p || typeof p !== 'object') throw new Error('Hiányzó adatok.');
  if (!/^\d{4}-\d{2}-\d{2}$/.test(p.date||'')) throw new Error('Hibás dátum.');
  const [y,m,d]=p.date.split('-').map(Number), dt=new Date(Date.UTC(y,m-1,d));
  if (dt.toISOString().slice(0,10)!==p.date) throw new Error('Nem létező dátum.');
  if (!CURRENCIES.includes(p.currency)) throw new Error('Válassz pénznemet.');
  if (typeof p.full !== 'boolean') throw new Error('Hiányzó tele tank jelölés.');
  const odometer=number_(p.odometer,'Km-óra');
  if (!Number.isSafeInteger(odometer) || odometer>9999999) throw new Error('A km-óra egész szám legyen.');
  const unitPrice=number_(p.unitPrice,'Literár'), total=number_(p.total,'Fizetett összeg');
  if (total/unitPrice>200 || total/unitPrice<0.1) throw new Error('A számított liter szokatlan. Ellenőrizd az árat és a végösszeget.');
  if (p.eInvoice != null && typeof p.eInvoice !== 'boolean') throw new Error('Hibás e-számla jelölés.');
  const rawNote=String(p.note == null ? '' : p.note).trim();
  const note=[p.eInvoice ? 'E-számla' : '',rawNote ? text_(rawNote,'Megjegyzés',500) : ''].filter(Boolean).join(' ');
  if (note.length>500) throw new Error('A megjegyzés túl hosszú.');
  if (p.full && /nem\s*teli\s*tank/i.test(note)) throw new Error('A megjegyzés nem tele tankot jelez: vedd ki a pipát.');
  const time=String(p.time||'');
  if(time && !/^([01]\d|2[0-3]):[0-5]\d$/.test(time)) throw new Error('Hibás idő.');
  const fuel=String(p.fuel == null ? '' : p.fuel).trim();
  return {date:p.date,dateSerial:dt.getTime()/86400000+25569,brand:text_(p.brand,'Márka',80),place:text_(p.place,'Hely',120),fuel:fuel?text_(fuel,'Üzemanyag',80):'',currency:p.currency,full:p.full,odometer,unitPrice,total,note,time};
}

function sameRecord_(r,p) {
  const v=r.values;
  return dateText_(v[0])===p.date && v[2]===p.brand && v[3]===p.place && v[4]===p.unitPrice && v[5]===p.total && v[7]===p.odometer && v[11]===p.currency;
}

function addOption_(sheet,column,value) {
  const values=sheet.getRange(2,column,199,1).getValues().flat();
  if(values.includes(value)) return;
  const empty=values.findIndex(v=>v==='');
  if(empty<0) throw new Error('A kútlista megtelt. Bővítsd a Listák lapot.');
  sheet.getRange(empty+2,column).setValue(value);
}

function addFuelOption_(sheet,value) {
  const options=fuelOptions_(sheet);
  if (!value || options.includes(value)) return;
  const rule=sheet.getRange('K2').getDataValidation().copy()
    .requireValueInList(options.concat([value]),true).build();
  sheet.getRange(2,11,sheet.getMaxRows()-1,1).setDataValidation(rule);
}

function consumptionFormula_(row,records,full) {
  if(!full) return '';
  const previous=records.slice().reverse().find(r=>r.values[12]===true && typeof r.values[7]==='number' && r.values[7]>0);
  if(!previous) return '';
  return '=IFERROR(SUM(G'+(previous.row+1)+':G'+row+')/(H'+row+'-H'+previous.row+')*100;"")';
}

function assertPreparedRow_(values, formulas, row) {
  const occupied = values.map((value, column) => {
    const formula = formulas[column] || '';
    if ([6,8,9].includes(column)) return !formula && value !== '';
    if (column === 11) return !!formula || !['',...CURRENCIES].includes(value);
    if (column === 12) return !!formula || !['',true,false].includes(value);
    return !!formula || value !== '';
  });
  const column = occupied.findIndex(Boolean);
  if (column !== -1) throw new Error('A következő sor '+String.fromCharCode(65+column)+row+' cellájában már adat van. A mentés leállt az adatok védelmében.');
}

function saveFuel(payload) {
  authorize_();
  const p=normalize_(payload), lock=LockService.getScriptLock();
  lock.waitLock(20000);
  try {
    const book=workbook_(), sheet=book.getSheetByName('Tankolások'), records=history_(sheet);
    const duplicate=records.find(r=>sameRecord_(r,p));
    if(duplicate) {
      const expectedNote=p.full?p.note:['Nem teli tank!',p.note].filter(Boolean).join(' ');
      if(duplicate.values[10]!==p.fuel || duplicate.values[12]!==p.full || String(duplicate.values[13]||'')!==expectedNote) throw new Error('Ez a tankolás már szerepel, de más üzemanyaggal, tele tank jelöléssel vagy megjegyzéssel. A meglévő sort a táblázatban javítsd.');
      return {alreadySaved:true,row:duplicate.row,liters:p.total/p.unitPrice,odometer:p.odometer};
    }
    const last=records[records.length-1];
    if(p.date>Utilities.formatDate(new Date(),ZONE,'yyyy-MM-dd')) throw new Error('Jövőbeli tankolást nem lehet menteni.');
    if(last && p.date<dateText_(last.values[0])) throw new Error('Ez régebbi az utolsó tankolásnál. Visszamenőleges bejegyzést a táblázatban rögzíts.');
    const maxKm=Math.max(0,...records.map(r=>typeof r.values[7]==='number'?r.values[7]:0));
    if(p.odometer<=maxKm) throw new Error('A km-óra legyen nagyobb az utolsó értéknél: '+maxKm+' km.');
    fuelOptions_(sheet); // Verify the existing list before any write.
    const row=last?last.row+1:2;
    if(row>sheet.getMaxRows()) throw new Error('Elfogytak az előkészített sorok. Bővítsd a táblázatot.');
    const target=sheet.getRange(row,1,1,14), current=target.getValues()[0], formulas=target.getFormulas()[0];
    assertPreparedRow_(current,formulas,row);
    const lists=book.getSheetByName('Listák');
    addOption_(lists,1,p.brand); addOption_(lists,2,p.place);
    addFuelOption_(sheet,p.fuel);
    // Apply safe presentation/constraints before the single row-content write.
    const exemplar=sheet.getRange(Math.max(2,row-1),1,1,14);
    exemplar.copyTo(target,SpreadsheetApp.CopyPasteType.PASTE_FORMAT,false);
    exemplar.copyTo(target,SpreadsheetApp.CopyPasteType.PASTE_DATA_VALIDATION,false);
    sheet.getRange(row,12).setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(CURRENCIES,true).setAllowInvalid(false).build());
    sheet.getRange(row,1).setNumberFormat('yyyy.mm.dd.');
    sheet.getRange(row,2).setNumberFormat('hh:mm');
    sheet.getRange(row,5).setNumberFormat('#,##0.00" '+currencyLabel_(p.currency)+'/l"');
    sheet.getRange(row,6).setNumberFormat('#,##0.00" '+currencyLabel_(p.currency)+'"');
    sheet.getRange(row,7).setNumberFormat('#,##0.00" l"');
    sheet.getRange(row,8,1,2).setNumberFormat('#,##0" km"');
    sheet.getRange(row,10).setNumberFormat('0.00" l/100 km"');
    const time=p.time?p.time.split(':').map(Number):null;
    const note=p.full?p.note:['Nem teli tank!',p.note].filter(Boolean).join(' ');
    const values=[p.dateSerial,time?(time[0]*60+time[1])/1440:'',p.brand,p.place,p.unitPrice,p.total,
      '=IFERROR(F'+row+'/E'+row+';"")',p.odometer,maxKm?'=H'+row+'-'+maxKm:'',
      consumptionFormula_(row,records,p.full),p.fuel,p.currency,p.full,note];
    target.setValues([values]);
    SpreadsheetApp.flush();
    return {alreadySaved:false,row,liters:p.total/p.unitPrice,distance:maxKm?p.odometer-maxKm:null,odometer:p.odometer};
  } finally {lock.releaseLock();}
}
