import {
  faArrowDown,
  faArrowUp,
  faCode,
  faPause,
  faPlay,
  faRotateLeft,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useRef, useState } from "react";

const capitalize = (str: string) => {
  if (str.length) {
    return str[0].toLocaleUpperCase() + str.slice(1).toLocaleLowerCase();
  }
  return str;
};
interface Timer {
  name: string;
  length: number;
  incrementLength: any; // To-DO: specify type
  decrementLength: any; // To-DO: specify type
  colorTheme: string;
}

function TimerControl({
  name,
  length,
  incrementLength,
  decrementLength,
  colorTheme,
}: Timer) {
  return (
    <div id={name} className="col">
      <h2 id={`${name}-label`} className="mcw">{`${capitalize(
        name
      )} Length`}</h2>
      <div id={`${name}_buttons_and_value`} className="mcw row py-2">
        <div className="col">
          <button
            type="button"
            className={`btn btn-${colorTheme}`}
            id={`${name}-decrement`}
            onClick={incrementLength}
          >
            <FontAwesomeIcon icon={faArrowUp} />
          </button>
        </div>
        <span
          id={`${name}-length`}
          className={`col h4 mx-2 py-1 px-3 bg-light border border-${colorTheme}`}
        >
          {length}
        </span>
        <div className="col">
          <button
            type="button"
            className={`btn btn-${colorTheme}`}
            id={`${name}-increment`}
            onClick={decrementLength}
          >
            <FontAwesomeIcon icon={faArrowDown} />
          </button>
        </div>
      </div>
    </div>
  );
}

interface State {
  session: boolean;
  running: boolean;
  sessionLength: number;
  breakLength: number;
  countdown: number;
  bgColor: string;
}

enum BgColors {
  Paused = "bg-primary",
  Session = "bg-success",
  Break = "bg-warning",
}

export default function Clock() {
  const SECS_IN_A_MIN = 60;
  const DEFAULT_SESSION_LENGTH = 25;
  const DEFAULT_BREAK_LENGTH = 5;
  const [state, setState] = useState<State>({
    session: true,
    running: false,
    sessionLength: DEFAULT_SESSION_LENGTH,
    breakLength: DEFAULT_BREAK_LENGTH,
    countdown: DEFAULT_SESSION_LENGTH * SECS_IN_A_MIN,
    bgColor: BgColors.Paused,
  });
  const beepRef = useRef<HTMLAudioElement>(null);
  const countdownRef = useRef<NodeJS.Timer | null>(null);

  const resetCounter = () => {
    beepRef.current?.pause();
    beepRef.current?.fastSeek(0);
    if (countdownRef.current) clearInterval(countdownRef.current);
    setState(() => ({
      session: true,
      running: false,
      sessionLength: DEFAULT_SESSION_LENGTH,
      breakLength: DEFAULT_BREAK_LENGTH,
      countdown: DEFAULT_SESSION_LENGTH * SECS_IN_A_MIN,
      bgColor: BgColors.Paused,
    }));
  };

  const startCounter = () => {
    if (countdownRef.current) clearInterval(countdownRef.current);
    countdownRef.current = setInterval(() => {
      setState((prevState) => {
        if (prevState.countdown <= 0) {
          const wasSession = prevState.session;
          beepRef.current?.play();
          return {
            ...prevState,
            session: !wasSession,
            running: true,
            countdown:
              (wasSession ? prevState.breakLength : prevState.sessionLength) *
              SECS_IN_A_MIN,
            bgColor: wasSession ? BgColors.Break : BgColors.Session,
          };
        } else {
          return { ...prevState, countdown: prevState.countdown - 1 };
        }
      });
    }, 1000);
    setState((prevState) => ({
      ...prevState,
      running: true,
      countdown: prevState.countdown - 1,
      bgColor: prevState.session ? BgColors.Session : BgColors.Break,
    }));
  };

  const stopCounter = () => {
    if (countdownRef.current) clearInterval(countdownRef.current);
    setState((prevState) => ({
      ...prevState,
      running: false,
      bgColor: BgColors.Paused,
    }));
  };

  const incrementSessionLength = () => {
    setState((prevState) => {
      if (prevState.running) return prevState;
      const sessionLength = Math.min(prevState.sessionLength + 1, 60);
      return {
        ...prevState,
        sessionLength: sessionLength,
        countdown: prevState.session
          ? sessionLength * SECS_IN_A_MIN
          : prevState.countdown,
      };
    });
  };

  const decrementSessionLength = () => {
    setState((prevState) => {
      if (prevState.running) return prevState;
      const sessionLength = Math.max(prevState.sessionLength - 1, 1);
      return {
        ...prevState,
        sessionLength: sessionLength,
        countdown: prevState.session
          ? sessionLength * SECS_IN_A_MIN
          : prevState.countdown,
      };
    });
  };

  const incrementBreakLength = () => {
    setState((prevState) => {
      if (prevState.running) return prevState;
      const breakLength = Math.min(prevState.breakLength + 1, 60);
      return {
        ...prevState,
        breakLength: breakLength,
        countdown: prevState.session
          ? prevState.countdown
          : breakLength * SECS_IN_A_MIN,
      };
    });
  };

  const decrementBreakLength = () => {
    setState((prevState) => {
      if (prevState.running) return prevState;
      const breakLength = Math.max(prevState.breakLength - 1, 1);
      return {
        ...prevState,
        breakLength: breakLength,
        countdown: prevState.session
          ? prevState.countdown
          : breakLength * SECS_IN_A_MIN,
      };
    });
  };

  return (
    <div id="background" className={state.bgColor}>
      <div
        id="center"
        className="d-flex align-items-center justify-content-center min-vh-100 text-center container"
      >
        <div id="content:">
          <div id="main" className="bg-white p-4 rounded-4">
            <div id="head">
              <h1 className="mcw display-1 text-primary">25 + 5 Clock</h1>
            </div>
            <div id="controls" className="row py-2 ">
              <TimerControl
                name="session"
                length={state.sessionLength}
                incrementLength={incrementSessionLength}
                decrementLength={decrementSessionLength}
                colorTheme="success"
              />
              <TimerControl
                name="break"
                length={state.breakLength}
                incrementLength={incrementBreakLength}
                decrementLength={decrementBreakLength}
                colorTheme="warning"
              />
            </div>
            <div id="display">
              <h2 id="timer-label" className="mcw">
                {state.session ? "Session" : "Break"}
              </h2>
              <h1 id="time-left" className={`mcw display-2`}>
                {`${String(
                  Math.floor(state.countdown / SECS_IN_A_MIN)
                ).padStart(2, "0")}:${String(
                  state.countdown % SECS_IN_A_MIN
                ).padStart(2, "0")}`}
              </h1>
              <div id="countdown_controls">
                <button
                  type="button"
                  className="btn btn-primary mx-2"
                  id="start_stop"
                  onClick={() => {
                    state.running ? stopCounter() : startCounter();
                  }}
                >
                  <FontAwesomeIcon icon={state.running ? faPause : faPlay} />
                </button>
                <button
                  type="button"
                  className="btn btn-primary mx-2"
                  id="reset"
                  onClick={resetCounter}
                >
                  <FontAwesomeIcon icon={faRotateLeft} />
                </button>
              </div>
              <audio
                id="beep"
                ref={beepRef}
                src="/timer_beep.wav"
                preload="auto"
              />
            </div>
          </div>
          <div id="footer">
            <p className="mcw my-3">
              <a
                className={
                  state.session || !state.running ? "link-light" : "link-dark"
                }
                href="https://radii.dev/freeCodeCamp.org-Front-End-Dev-Libraries/Build-a-25-plus-5-Clock"
              >
                <FontAwesomeIcon icon={faCode} /> Source Code & License
              </a>
            </p>
          </div>
        </div>
      </div>
    </div>
  );
}
