import { Layout, makeScene2D } from "@motion-canvas/2d";
import {
  Direction,
  all,
  beginSlide,
  createRef,
  slideTransition,
} from "@motion-canvas/core";

import { FunctionBox } from "../components/function_box";
import { PEOPLE, Person, PersonI } from "../components/person";
import { CardI, daysUntilNextDate } from "./birthday_letters";

export const valentineCardFn = (person: PersonI): CardI => {
  const valentinesDay = new Date("02/14/2024");
  const message =
    `Dear, ${person.name}\n.` +
    "Your smile lights up my world.\n" +
    "Happy Valentine's Day!";
  const deliverInDays = daysUntilNextDate(valentinesDay);
  return { message, deliverInDays };
};

export const birthdayCardFn = (person: PersonI): CardI => {
  const age = new Date().getFullYear() - person.birthday.getFullYear();
  const ending =
    ({ 1: "st", 2: "nd", 3: "rd" } as Record<number, string>)[
      parseInt(Array.from(age.toString()).at(-1))
    ] ?? "th";
  const message =
    `Happy ${age}${ending} birthday, ${person.name}!\n` +
    "I can't believe it's already been a year!";

  const deliverInDays = daysUntilNextDate(person.birthday);
  return { deliverInDays, message };
};

const valentineCardGenerator = `const valentineCardGenerator = (person: PersonI): CardI => {
  const valentinesDay = new Date("02/14/2024");
  const message =
    \`Dear, \${person.name}\\n.\` +
    "Your smile lights up my world.\\n" +
    "Happy Valentine's Day!";
  const deliverInDays = daysUntilNextDate(valentinesDay);
  return { message, deliverInDays };
};`;

const birthdayCardGenerator = `const birthdayCardGenerator = (person: PersonI): CardI => {
  const age = new Date().getFullYear() - person.birthday.getFullYear();
  const ageEnding = (
    { 1: "st", 2: "nd", 3: "rd" } as Record<number, string>
  )[parseInt(Array.from(age.toString()).at(-1))] ?? "th";

  const message =
    \`Happy \${age}\${ageEnding} birthday, \${person.name}!\\n\` +
    "I can't believe it's already been a year!";

  const deliverInDays = daysUntilNextDate(person.birthday);
  return { deliverInDays, message };
}`;

const cardBuilder = `const buildCards = (
  people: PersonI[],
  cardGenerator: (person: PersonI) => CardI,
): CardI[] => {
  const cards: CardI[] = [];

  for (const person of people) {
    const card = cardGenerator(person);
    cards.push(card);
  }

  return cards;
};
buildCards;`;

export default makeScene2D(function* (view) {
  const valentineFunctionBox = createRef<FunctionBox>();
  const birthdayFunctionBox = createRef<FunctionBox>();
  const cardBuilderBox = createRef<FunctionBox>();
  const layout = createRef<Layout>();

  view.add(
    <Layout direction="row" gap={200} ref={layout} layout>
      <Layout direction="column" alignItems="center" gap={20}>
        <FunctionBox
          ref={valentineFunctionBox}
          source={valentineCardGenerator}
          fn={valentineCardFn}
          idlingText="❤️"
          workingText="📝⚙"
          outputFontSize={15}
        ></FunctionBox>
        <FunctionBox
          ref={birthdayFunctionBox}
          source={birthdayCardGenerator}
          fn={birthdayCardFn}
          idlingText="🎂"
          workingText="📝⚙"
          outputFontSize={15}
        ></FunctionBox>
      </Layout>
      <Layout direction="column" gap={20}>
        <FunctionBox
          ref={cardBuilderBox}
          source={cardBuilder}
          idlingText="🏭"
          workingText="📝⚙"
          outputFontSize={15}
          arity={2}
        ></FunctionBox>
      </Layout>
    </Layout>,
  );

  yield* all(
    slideTransition(Direction.Left),
    ...[valentineFunctionBox, birthdayFunctionBox, cardBuilderBox].map((x) =>
      x().reset(0.1),
    ),
  );

  yield* beginSlide("show all functions");

  yield* all(
    ...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
      x().showCode(0.5),
    ),
  );

  yield* beginSlide("show generator functions");

  const [p1, p2, p3, p4] = PEOPLE;
  yield* all(
    ...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
      x().hideCode(0.5),
    ),
  );
  yield* all(
    ...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
      x().setInputs([{ val: p2, node: <Person person={p2} /> }], 0.5),
    ),
  );

  yield* beginSlide("show inputs");

  yield* all(
    ...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
      x().propogateInput(0.5),
    ),
  );
  yield* all(
    ...[valentineFunctionBox, birthdayFunctionBox].map((x) =>
      x().propogateOutput(0.5),
    ),
  );
  yield* beginSlide("make cards");

  yield* all(
    ...[valentineFunctionBox, birthdayFunctionBox].map((x) => x().reset(0.5)),
    cardBuilderBox().showCode(0.5),
  );

  yield* beginSlide("hide cards, show card generator");

  yield* cardBuilderBox().setInputs(
    [
      {
        val: [p1, p2],
        node: (
          <Layout direction="row" gap={20}>
            <Person person={p1} />
            <Person person={p2} />
          </Layout>
        ),
      },
      { val: valentineCardFn, node: valentineFunctionBox() },
    ],
    0.5,
  );
  yield* beginSlide("input function to function");

  yield* cardBuilderBox().hideCode(0.5);
  yield* cardBuilderBox().propogateInput(0.5);
  yield* cardBuilderBox().propogateOutput(0.5);

  yield* beginSlide("build valentines cards");

  yield* all(layout().gap(0, 0.5), cardBuilderBox().reset(0.5));
  yield* cardBuilderBox().setInputs(
    [
      {
        val: [p2, p3, p4],
        node: (
          <Layout direction="row" gap={20}>
            <Person person={p2} />
            <Person person={p3} />
            <Person person={p4} />
          </Layout>
        ),
      },
      { val: birthdayCardFn, node: birthdayFunctionBox() },
    ],
    0.5,
  );
  yield* beginSlide("show birthday cards input");

  yield* cardBuilderBox().propogateInput(0.5);
  yield* cardBuilderBox().propogateOutput(0.5);

  yield* beginSlide("build cards");
});
