`;
contentHtml += `
II. Projected Annual Income
Average Nightly Rate: ${air_formatCurrency(inputs.income.avgNightlyRate)}
Expected Occupancy Rate: ${air_formatPercentage(inputs.income.occupancyRate)}
Gross Annual Rental Income: ${air_formatCurrency(results.grossAnnualRentalIncome)}
Other Annual Income: ${air_formatCurrency(inputs.income.otherAnnualIncome)}
Total Gross Income: ${air_formatCurrency(results.totalGrossIncome)}
`;
contentHtml += `
III. Projected Annual Operating Expenses
Property Management (${inputs.expenses.mgmtFeeType === 'percent' ? inputs.expenses.mgmtFeeValue + '%' : 'Fixed $'}): ${air_formatCurrency(results.propertyMgmtFee)}
Platform Fees (${air_formatPercentage(inputs.expenses.platformFeePercent)}): ${air_formatCurrency(results.platformFees)}
Utilities: ${air_formatCurrency(results.utilitiesAnnual)}
Insurance: ${air_formatCurrency(results.insuranceAnnual)}
Property Taxes: ${air_formatCurrency(results.propertyTaxesAnnual)}
Supplies: ${air_formatCurrency(results.suppliesAnnual)}
Maintenance (${inputs.expenses.maintenanceType === 'percent' ? inputs.expenses.maintenanceValue + '%' : 'Fixed $'}): ${air_formatCurrency(results.maintenanceCosts)}
Cleaning Costs: ${air_formatCurrency(results.cleaningCostsAnnual)}
${inputs.expenses.hoaFeesAnnual > 0 ? `
HOA Fees: ${air_formatCurrency(inputs.expenses.hoaFeesAnnual)}
` : ''}
${inputs.expenses.otherOpExAnnual > 0 ? `
Other OpEx: ${air_formatCurrency(inputs.expenses.otherOpExAnnual)}
` : ''}
Total Operating Expenses: ${air_formatCurrency(results.totalOperatingExpenses)}
`;
contentHtml += `
IV. Financial Performance Summary (Annual)
Net Operating Income (NOI): ${air_formatCurrency(results.noi)}
${inputs.property.loanAmount > 0 ? `
Est. Annual Mortgage Payment: (${air_formatCurrency(results.annualMortgagePayment)})
` : ''}
Cash Flow (Before Tax): ${air_formatCurrency(results.cashFlowBeforeTax)}
Cap Rate: ${air_formatPercentage(results.capRate)}
${inputs.property.downPayment !== null ? `
Cash-on-Cash Return: ${isFinite(results.cashOnCashReturn) ? air_formatPercentage(results.cashOnCashReturn) : "N/A"}
` : ''}
`;
const interpretationNote_pdf = `Estimates are based on user inputs. Actual performance can vary significantly. This is not financial advice.`;
const disclaimer_pdf = document.getElementById('air_interpretation_note_container').innerText.replace("Understanding Your Results:", "").trim();
pdfContentEl.innerHTML = `
${contentHtml}
Important Notes: ${disclaimer_pdf.replace(/\n/g, "
")}
`;
document.body.appendChild(pdfContentEl);
html2canvas(pdfContentEl, { scale: 2, useCORS: true, logging:true, windowWidth: pdfContentEl.scrollWidth, windowHeight: pdfContentEl.scrollHeight }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const imgProps = pdf.getImageProperties(imgData);
let numPages = Math.ceil(imgProps.height / ( (pdfHeight - 40) * (imgProps.width / (pdfWidth - 40)) ) );
let pageCanvasHeight = (pdfHeight - 40) * (imgProps.width / (pdfWidth - 40));
for (let i = 0; i < numPages; i++) {
if (i > 0) pdf.addPage();
let sourceY = i * pageCanvasHeight;
let sourceHeight = Math.min(pageCanvasHeight, imgProps.height - sourceY);
const tempCanvas = document.createElement('canvas');
tempCanvas.width = imgProps.width;
tempCanvas.height = sourceHeight;
const ctx = tempCanvas.getContext('2d');
ctx.drawImage(canvas, 0, sourceY, imgProps.width, sourceHeight, 0, 0, imgProps.width, sourceHeight);
const pageImgData = tempCanvas.toDataURL('image/png');
const pageImgHeight = (sourceHeight * (pdfWidth - 40)) / imgProps.width;
pdf.addImage(pageImgData, 'PNG', 20, 20, pdfWidth - 40, pageImgHeight, undefined, 'FAST');
}
pdf.save('Airbnb_Investment_Return_Analysis.pdf');
if(document.body.contains(pdfContentEl)) document.body.removeChild(pdfContentEl);
}).catch(err => {
console.error("Airbnb ROI PDF Error:", err); alert("Error generating PDF. See console.");
if(document.body.contains(pdfContentEl)) document.body.removeChild(pdfContentEl);
});
}
document.addEventListener('DOMContentLoaded', function() {
air_openTab({}, 'air_tab_property');
// Default some values for easier testing
const purchasePriceEl = document.getElementById('air_purchasePrice');
if (purchasePriceEl && !purchasePriceEl.value) purchasePriceEl.value = '200000';
const initialCostsEl = document.getElementById('air_initialCosts');
if (initialCostsEl && !initialCostsEl.value) initialCostsEl.value = '10000';
const nightlyRateEl = document.getElementById('air_avgNightlyRate');
if (nightlyRateEl && !nightlyRateEl.value) nightlyRateEl.value = '120';
const occupancyEl = document.getElementById('air_occupancyRate');
if (occupancyEl && !occupancyEl.value) occupancyEl.value = '60';
const platformFeeEl = document.getElementById('air_platformFeePercent');
if (platformFeeEl && !platformFeeEl.value) platformFeeEl.value = '3';
if (!document.getElementById('air_purchasePrice')) {
console.error("Critical input 'air_purchasePrice' not found.");
}
});