/**
 * The two flat things: a rug on the floor and a board on the wall.
 *
 * Neither is part of the shell. A room's floor finish and its walls come from
 * the `Floorplan` (CONTRACT.md §2); a rug is a prop laid on top of whatever the
 * room's floor already is, which is exactly how a rug works.
 */

import { defineAsset } from "../kit.ts";
import { MeshBin } from "../parts.ts";
import { panelSlab, tintable } from "./common.ts";

type RugParams = {
  width: number;
  depth: number;
  /** Pile thickness. Small, but not zero — a rug at zero z-fights the floor. */
  pile: number;
  /** A plain band of the base carpet around the tinted field. */
  border: boolean;
};

/** The pile is the tintable part; the border, when there is one, is not. */
export const rug = defineAsset<RugParams>({
  id: "tera:rug",
  label: "Rug",
  defaults: { width: 2.4, depth: 1.7, pile: 0.014, border: true },

  footprint(p) {
    return { width: p.width, depth: p.depth, height: p.pile };
  },

  build(p, ctx) {
    const bin = new MeshBin();
    const field = tintable(ctx, "carpetAccent");
    const edge = ctx.materials.get("carpet");

    bin.add(ctx.parts.box(), field, { size: [p.width, p.pile, p.depth] });

    if (p.border) {
      const band = Math.min(0.12, Math.min(p.width, p.depth) * 0.08);
      bin.add(ctx.parts.metricQuad(p.width, p.depth), edge, { y: p.pile + 0.0006 });
      bin.add(ctx.parts.metricQuad(p.width - band * 2, p.depth - band * 2), field, {
        y: p.pile + 0.0012,
      });
    } else {
      bin.add(ctx.parts.metricQuad(p.width, p.depth), field, { y: p.pile + 0.0006 });
    }

    return bin.build("rug", { castShadow: false });
  },
});

type WhiteboardParams = {
  width: number;
  height: number;
  /** Floor to the bottom edge of the writing surface. */
  mount: number;
  tray: boolean;
};

/**
 * A wall-hung board. Authored standing on the floor with the writing surface
 * from `mount` up, so a pack places it against the wall and never has to work
 * out how high a whiteboard goes.
 *
 * The −Z face is skipped: it is against a wall, and drawing it would put a
 * second sheet of whiteboard texture into the merge for a surface nobody can
 * ever see.
 */
export const whiteboard = defineAsset<WhiteboardParams>({
  id: "tera:whiteboard",
  label: "Whiteboard",
  defaults: { width: 1.8, height: 1.2, mount: 0.9, tray: true },

  footprint(p) {
    return { width: p.width, depth: 0.1, height: p.mount + p.height };
  },

  build(p, ctx) {
    const P = ctx.parts;
    const bin = new MeshBin();
    const trim = ctx.materials.get("metalTrim");

    panelSlab(bin, ctx, ctx.materials.get("whiteboard"), {
      y: p.mount,
      width: p.width - 0.05,
      height: p.height - 0.05,
      thickness: 0.022,
      faces: "front",
    });

    const bar = 0.025;
    for (const s of [-1, 1]) {
      bin.add(P.box(), trim, {
        y: p.mount + (s < 0 ? 0 : p.height - bar),
        size: [p.width, bar, 0.03],
      });
      bin.add(P.box(), trim, {
        x: (s * (p.width - bar)) / 2,
        y: p.mount,
        size: [bar, p.height, 0.03],
      });
    }

    if (p.tray) {
      bin.add(P.box(), trim, {
        y: p.mount - 0.03,
        z: 0.035,
        size: [p.width * 0.55, 0.016, 0.07],
      });
      const pens = ctx.materials.get("accent");
      for (let i = 0; i < 3; i++) {
        // Rolled a quarter turn, a rod lies along −X from where it is placed.
        bin.add(P.rod(), pens, {
          x: 0.02 + i * 0.045,
          y: p.mount - 0.014,
          z: 0.04,
          size: [0.014, 0.13, 0.014],
          roll: Math.PI / 2,
        });
      }
    }

    return bin.build("whiteboard");
  },
});
