function urlToTopic() {
  const path = window.location.pathname;
  const pathParts = path.split("/");
  return pathParts[2];
}

function getTextColor() {
  return getComputedStyle(document.documentElement)
    .getPropertyValue("--text")
    .trim();
}

function setUpParameters(render, parameters, modelPrefix) {
  parameters.forEach((param) => {
    const slider = document.getElementById(`slider${modelPrefix}${param}`);
    slider.oninput = function () {
      slider.previousElementSibling.innerText = this.value;
      render();
    };
  });
  return parameters.map((param) => {
    return parseFloat(
      document.getElementById(`output${modelPrefix}${param}`).textContent,
    );
  });
}

function drawSolowGraph() {
  const L = 150,
    K_MAX = 500,
    margin = { top: 50, right: 55, bottom: 40, left: 75 };

  const [A, d, s, alpha] = setUpParameters(
    drawSolowGraph,
    ["A", "d", "s", "alpha"],
    "S",
  );
  const solowOutput = (K) => A * Math.pow(K, alpha) * Math.pow(L, 1 - alpha);
  const solowDepreciation = (K) => d * K;
  const solowInvestment = (Y) => s * Y;

  const container = document.getElementById("solow-visualization");

  const width = container.clientWidth - margin.left - margin.right;
  const height = container.clientHeight - margin.top - margin.bottom;

  container.innerHTML = "";

  const svg = d3
    .select("#solow-visualization")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", `translate(${margin.left}, ${margin.top})`);

  const x = d3.scaleLinear().domain([0, K_MAX]).range([0, width]);
  const xAxis = svg
    .append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x));
  xAxis.selectAll("text").style("font-size", "1.5em");
  xAxis
    .append("text")
    .attr("x", width + 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .style("font-size", "2em")
    .text("K");

  const Y_MAX = solowOutput(K_MAX) + K_MAX / 10;
  const y = d3.scaleLinear().domain([0, Y_MAX]).range([height, 0]);
  const yAxis = svg.append("g").call(d3.axisLeft(y));
  yAxis.selectAll("text").style("font-size", "1.5em");
  yAxis
    .append("text")
    .attr("x", 0)
    .attr("y", -10)
    .style("text-anchor", "start")
    .style("font-size", "2em")
    .text("Y");

  const outputData = Array.from({ length: K_MAX }, (_, k) => ({
    K: k,
    Y: solowOutput(k),
  }));
  svg
    .append("path")
    .datum(outputData)
    .attr("fill", "none")
    .attr("stroke", window.getTopicColor(urlToTopic()))
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.K))
        .y((d) => y(d.Y)),
    );
  svg
    .append("foreignObject")
    .attr("width", "2em")
    .attr("height", "2em")
    .attr("x", x(K_MAX))
    .attr("y", y(outputData[K_MAX - 1].Y))
    .append("xhtml:body")
    .style("font-size", "0.75em")
    .text("Y");

  const depreciationData = Array.from({ length: K_MAX }, (_, k) => ({
    K: k,
    Y: solowDepreciation(k),
  }));
  svg
    .append("path")
    .datum(depreciationData)
    .attr("fill", "none")
    .attr("stroke", "red")
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.K))
        .y((d) => y(d.Y)),
    );

  svg
    .append("foreignObject")
    .attr("width", "2em")
    .attr("height", "2em")
    .attr("x", x(K_MAX))
    .attr("y", y(depreciationData[K_MAX - 1].Y))
    .append("xhtml:body")
    .style("font-size", "0.75em")
    .append("xhtml:div")
    .text("dK");

  const investmentData = outputData.map((d) => ({
    K: d.K,
    Y: solowInvestment(d.Y),
  }));
  svg
    .append("path")
    .datum(investmentData)
    .attr("fill", "none")
    .attr("stroke", "purple")
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.K))
        .y((d) => y(d.Y)),
    );

  svg
    .append("text")
    .attr("x", x(K_MAX))
    .attr("y", y(investmentData[K_MAX - 1].Y))
    .style("font-size", "0.75em")
    .text("I");

  const k_star = L * Math.pow((s * A) / d, 1 / (1 - alpha));
  svg
    .append("line")
    .attr("x1", x(k_star))
    .attr("y1", y((d * k_star) / s))
    .attr("x2", x(k_star))
    .attr("y2", y(0))
    .attr("stroke-width", 1)
    .attr("stroke-dasharray", "5,5");

  const y_star = solowOutput(k_star);
  svg
    .append("text")
    .attr("x", x(k_star) - 40)
    .attr("y", y(y_star) - 40)
    .style("font-size", "0.75em")
    .text(`(${k_star.toFixed(0)}, ${y_star.toFixed(0)})`);
}

const formatNumber = (num) => {
  return `~${num.toExponential(0)}`;
};

const normalFont = `style="font-weight: normal"`;

const updateRomerTable = (romerData) => {
  const tableHeader = document.getElementById("romer-table-header");
  const rowA_t = document.getElementById("row-A_t");
  const rowY_t = document.getElementById("row-Y_t");

  tableHeader.innerHTML = `<th ${normalFont}>t</th>`;
  rowA_t.innerHTML = `<td class="romer-table-at">A_t</td>`;
  rowY_t.innerHTML = `<td class="romer-table-yt">Y_t</td>`;

  romerData.forEach((d) => {
    if (d.year % 20 === 0 || d.year === 1) {
      tableHeader.innerHTML += `<th ${normalFont}>${d.year}</th>`;
      rowA_t.innerHTML += `<td>${formatNumber(d.A)}</td>`;
      rowY_t.innerHTML += `<td>${formatNumber(d.Y)}</td>`;
    }
  });
};

function drawRomerGraph() {
  const T_MAX = 100,
    margin = { top: 50, right: 110, bottom: 40, left: 75 };

  const [z, L, l, A0] = setUpParameters(
    drawRomerGraph,
    ["z", "L", "l", "A0"],
    "R",
  );

  const container = document.getElementById("romer-visualization");
  const width = container.clientWidth - margin.left - margin.right;
  const height = container.clientHeight - margin.top - margin.bottom;

  container.innerHTML = "";

  const svg = d3
    .select("#romer-visualization")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", `translate(${margin.left}, ${margin.top})`);

  let A = A0;
  const romerData = [];

  for (let t = 1; t <= T_MAX; ++t) {
    const A_t = A * (1 + z * l * L);
    const Y_t = A_t * (1 - l) * L;
    romerData.push({ year: t, A: A_t, Y: Math.log10(Y_t) });
    A = A_t;
  }

  const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
  const xAxis = svg
    .append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x));
  xAxis.selectAll("text").style("font-size", "1.5em");
  xAxis
    .append("text")
    .attr("x", width + 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .style("font-size", "2em")
    .text("t");

  const y = d3
    .scaleLinear()
    .domain([0, romerData[romerData.length - 1].Y])
    .range([height, 0]);
  const yAxis = svg
    .append("g")
    .call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
  yAxis.selectAll("text").style("font-size", "1.5em");
  yAxis
    .append("text")
    .attr("x", 0)
    .attr("y", -10)
    .style("text-anchor", "start")
    .style("font-size", "2em")
    .text("log(Y)");

  svg
    .append("path")
    .datum(romerData)
    .attr("fill", "none")
    .attr("stroke", window.getTopicColor(urlToTopic()))
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.year))
        .y((d) => y(d.Y)),
    );

  svg
    .append("text")
    .attr("x", x(T_MAX))
    .attr("y", y(romerData[T_MAX - 1].Y))
    .style("font-size", "0.75em")
    .text("log10(Y)");

  updateRomerTable(romerData);
}

function drawRomerlGraph() {
  const T_MAX = 100,
    z = 0.01,
    L = 50,
    A0 = 50,
    margin = { top: 50, right: 110, bottom: 40, left: 75 };

  const [l, t0] = setUpParameters(drawRomerlGraph, ["lChange", "t0"], "");

  const container = document.getElementById("romer-lchange-visualization");
  const width = container.clientWidth - margin.left - margin.right;
  const height = container.clientHeight - margin.top - margin.bottom;

  container.innerHTML = "";

  const svg = d3
    .select("#romer-lchange-visualization")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", `translate(${margin.left}, ${margin.top})`);

  let A = A0,
    l_ = 0.1;
  const romerData = [];

  for (let t = 1; t <= t0; ++t) {
    const A_t = A * (1 + z * l_ * L);
    const Y_t = A_t * (1 - l_) * L;
    romerData.push({ year: t, A: A_t, Y: Math.log10(Y_t) });
    A = A_t;
  }

  for (let t = t0 + 1; t <= T_MAX; ++t) {
    const A_t = A * (1 + z * l * L);
    const Y_t = A_t * (1 - l) * L;
    romerData.push({ year: t, A: A_t, Y: Math.log10(Y_t) });
    A = A_t;
  }

  const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
  const xAxis = svg
    .append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x));
  xAxis.selectAll("text").style("font-size", "1.5em");
  xAxis
    .append("text")
    .attr("x", width + 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .style("font-size", "2em")
    .text("t");

  const y = d3
    .scaleLinear()
    .domain([0, romerData[romerData.length - 1].Y])
    .range([height, 0]);
  const yAxis = svg
    .append("g")
    .call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
  yAxis.selectAll("text").style("font-size", "1.5em");
  yAxis
    .append("text")
    .attr("x", 0)
    .attr("y", -10)
    .style("text-anchor", "start")
    .style("font-size", "2em")
    .text("log(Y)");

  svg
    .append("path")
    .datum(romerData)
    .attr("fill", "none")
    .attr("stroke", window.getTopicColor(urlToTopic()))
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.year))
        .y((d) => y(d.Y)),
    );

  svg
    .append("line")
    .attr("x1", x(t0))
    .attr("y1", y(romerData[T_MAX - 1].Y))
    .attr("x2", x(t0))
    .attr("y2", height)
    .attr("stroke-width", 1)
    .attr("stroke-dasharray", "4");

  svg
    .append("text")
    .attr("x", x(0) + 15)
    .attr("y", y(romerData[0].Y))
    .style("font-size", "0.6em")
    .text(`l0=${l_}`);

  svg
    .append("text")
    .attr("x", x(t0) + 15)
    .attr("y", y(romerData[t0].Y))
    .style("font-size", "0.6em")
    .text(`l1=${l}`);

  svg
    .append("text")
    .attr("x", x(T_MAX))
    .attr("y", y(romerData[T_MAX - 1].Y))
    .style("font-size", "0.75em")
    .text("log10(Y)");
}

function calculateRomerSolowData(
  T_MAX,
  L,
  l,
  A0,
  alpha,
  s,
  d,
  z,
  t0 = Infinity,
  L0,
  l0,
  alpha0,
  z0,
) {
  let A = A0,
    K_t = 1,
    romerSolowData = [];

  for (let t = 1; t <= T_MAX; ++t) {
    if (t > t0) {
      alpha = alpha0;
      z = z0;
      l = l0;
      L = L0;
    }

    const Y_t = A * Math.pow(K_t, alpha) * Math.pow((1 - l) * L, 1 - alpha);
    const A_t = A * (1 + z * l * L);
    K_t = K_t + s * Y_t - d * K_t;
    romerSolowData.push({ year: t, A: A_t, K: K_t, Y: Math.log10(Y_t) });
    A = A_t;
  }

  return romerSolowData;
}

function drawRomerSolowGraph() {
  const T_MAX = 100,
    margin = { top: 50, right: 110, bottom: 40, left: 75 };

  const [z, l, L, A0, s, d, alpha] = setUpParameters(
    drawRomerSolowGraph,
    ["z", "l", "L", "A0", "s", "d", "alpha"],
    "RS",
  );

  const container = document.getElementById("romer-solow-visualization");
  const width = container.clientWidth - margin.left - margin.right;
  const height = container.clientHeight - margin.top - margin.bottom;

  container.innerHTML = "";

  const svg = d3
    .select("#romer-solow-visualization")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", `translate(${margin.left}, ${margin.top})`);

  const romerSolowData = calculateRomerSolowData(
    T_MAX,
    L,
    l,
    A0,
    alpha,
    s,
    d,
    z,
  );

  const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
  const xAxis = svg
    .append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x));
  xAxis.selectAll("text").style("font-size", "1.5em");
  xAxis
    .append("text")
    .attr("x", width + 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .style("font-size", "2em")
    .text("t");

  const y = d3
    .scaleLinear()
    .domain([0, romerSolowData[romerSolowData.length - 1].Y])
    .range([height, 0]);
  const yAxis = svg
    .append("g")
    .call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
  yAxis.selectAll("text").style("font-size", "1.5em");
  yAxis
    .append("text")
    .attr("x", 0)
    .attr("y", -10)
    .style("text-anchor", "start")
    .style("font-size", "2em")
    .text("log(Y)");

  svg
    .append("path")
    .datum(romerSolowData)
    .attr("fill", "none")
    .attr("stroke", window.getTopicColor(urlToTopic()))
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.year))
        .y((d) => y(d.Y)),
    );

  svg
    .append("text")
    .attr("x", x(T_MAX))
    .attr("y", y(romerSolowData[T_MAX - 1].Y))
    .style("font-size", "0.75em")
    .text("log10(Y)");
}

function drawRomerSolowChangeGraph() {
  const T_MAX = 100,
    margin = { top: 20, right: 100, bottom: 20, left: 50 },
    s = 0.2,
    d = 0.2,
    A0 = 50,
    alpha = 0.33,
    l = 0.5,
    L = 100,
    z = 0.5;

  const [z0, l0, L0, alpha0, t0] = setUpParameters(
    drawRomerSolowChangeGraph,
    ["z0", "l0", "L0", "alpha0", "t0"],
    "RSC",
  );

  const container = document.getElementById("romer-solow-change-visualization");
  const width = container.clientWidth - margin.left - margin.right;
  const height = container.clientHeight - margin.top - margin.bottom;

  container.innerHTML = "";

  const svg = d3
    .select("#romer-solow-change-visualization")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", `translate(${margin.left}, ${margin.top})`);

  const romerSolowData = calculateRomerSolowData(
    T_MAX,
    L,
    l,
    A0,
    alpha,
    s,
    d,
    z,
    t0,
    L0,
    l0,
    alpha0,
    z0,
  );

  const x = d3.scaleLinear().domain([1, T_MAX]).range([0, width]);
  const xAxis = svg
    .append("g")
    .attr("transform", `translate(0, ${height})`)
    .call(d3.axisBottom(x));
  xAxis.selectAll("text").style("font-size", "1.5em");
  xAxis
    .append("text")
    .attr("x", width + 10)
    .attr("y", -10)
    .style("text-anchor", "end")
    .style("font-size", "2em")
    .text("t");

  const y = d3
    .scaleLinear()
    .domain([0, romerSolowData[romerSolowData.length - 1].Y])
    .range([height, 0]);
  const yAxis = svg
    .append("g")
    .call(d3.axisLeft(y).ticks(10, d3.format(".1s")));
  yAxis.selectAll("text").style("font-size", "1.5em");
  yAxis
    .append("text")
    .attr("x", 0)
    .attr("y", -10)
    .style("text-anchor", "start")
    .style("font-size", "2em")
    .text("log(Y)");

  svg
    .append("path")
    .datum(romerSolowData)
    .attr("fill", "none")
    .attr("stroke", window.getTopicColor(urlToTopic()))
    .attr("stroke-width", 2)
    .attr(
      "d",
      d3
        .line()
        .x((d) => x(d.year))
        .y((d) => y(d.Y)),
    );

  svg
    .append("line")
    .attr("x1", x(t0))
    .attr("y1", y(romerSolowData[T_MAX - 1].Y))
    .attr("x2", x(t0))
    .attr("y2", height)
    .attr("stroke-width", 1)
    .attr("stroke-dasharray", "4");

  svg
    .append("text")
    .attr("x", x(T_MAX))
    .attr("y", y(romerSolowData[T_MAX - 1].Y))
    .style("font-size", "0.75em")
    .text("log10(Y)");
}

drawSolowGraph();
drawRomerGraph();
drawRomerlGraph();
drawRomerSolowGraph();
drawRomerSolowChangeGraph();

window.onresize = () => {
  drawSolowGraph();
  drawRomerGraph();
  drawRomerlGraph();
  drawRomerSolowGraph();
  drawRomerSolowChangeGraph();
};

new MutationObserver(() => {
  drawSolowGraph();
  drawRomerGraph();
  drawRomerlGraph();
  drawRomerSolowGraph();
  drawRomerSolowChangeGraph();
}).observe(document.documentElement, {
  attributes: true,
  attributeFilter: ["data-theme"],
});
