"use client";
import {
  Box,
  Button,
  ButtonGroup,
  Grid,
  Input,
  Slider,
  Stack,
} from "@mui/material";
import React from "react";
import { StripBusOutput, StripBusOutputEvent } from "./StripBusOutput";
import { EventCounter } from "@/utils/EventCounter";

export interface StripProps {
  physicalBuses: number;
  virtualBuses: number;
  values?: Partial<StripState>;
  onChange: (event: StripEvent) => any;
}

export interface StripState {
  gain: number;
  outputBuses: boolean[];
  muted: boolean;
}

export type StripEvent = StripBusOutputChanged | StripMuted | StripGainChanged;

export interface StripBusOutputChanged extends StripBusOutputEvent {
  type: "StripBusOutputChanged";
}

export interface StripGainChanged {
  type: "StripGainChanged";
  gain: number;
}
export interface StripMuted {
  type: "StripMuted";
  muted: boolean;
}

export class Strip extends React.Component<StripProps, StripState> {
  private defaultValues: StripState;
  private eventCounter = new EventCounter<"onSliderResetDefaults">();
  constructor(props: StripProps) {
    super(props);
    const { values: initialValues } = props;
    this.defaultValues = {
      gain: 0,
      outputBuses: [...Array(props.physicalBuses + props.virtualBuses)].map(
        (_v, k) => false
      ),
      muted: false,
    };
    const getValue = (name: keyof typeof this.defaultValues) => {
      if (initialValues === undefined) return this.defaultValues[name];
      return initialValues[name] !== undefined
        ? this.defaultValues[name]
        : initialValues[name];
    };
    this.state = Object.fromEntries(
      Object.entries(this.defaultValues).map(([name]) => [
        name,
        getValue(name as keyof typeof this.defaultValues) as any,
      ])
    ) as StripState;
    this.eventCounter.on({
      callback: this.onResetDefaults.bind(this),
      count: 2,
      name: "onSliderResetDefaults",
    });
  }
  onResetDefaults() {
    this.setState({ gain: this.defaultValues.gain });
  }
  onSliderClick(event: React.MouseEvent) {
    this.stopPropagation(event);
    this.eventCounter.emit("onSliderResetDefaults");
  }
  onKeyDown(event: React.KeyboardEvent) {
    console.log(event);

    if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
      event.preventDefault();
    }
  }
  onGainChange(event: Event) {
    this.stopPropagation(event);
    const multiplier = (event as unknown as React.KeyboardEvent).shiftKey
      ? 2
      : 1;
    const changedGain =
      parseFloat((event.target as HTMLInputElement).value) * multiplier;
    this.setState({
      gain: changedGain,
    });
    this.props.onChange({
      type: "StripGainChanged",
      gain: changedGain,
    });
  }
  onBusChange(event: StripBusOutputEvent) {
    const buses = this.state.outputBuses;
    buses[
      event.isVirtual ? this.props.physicalBuses + event.busId : event.busId
    ] = event.enabled;
    this.setState({
      outputBuses: buses,
    });
    this.props.onChange({
      type: "StripBusOutputChanged",
      busId: event.busId,
      isVirtual: event.isVirtual,
      enabled: event.enabled,
    });
  }
  onStripWheel(event: React.WheelEvent) {
    console.log(event);
  }
  onMuteToggle(event: React.MouseEvent) {
    this.stopPropagation(event);
    this.setState(
      (state) => ({ muted: !state.muted }),
      () => {
        this.props.onChange({ type: "StripMuted", muted: this.state.muted });
      }
    );
  }
  stopPropagation(event: Event | React.MouseEvent) {
    if (event instanceof Event) event.stopImmediatePropagation();
    else event.nativeEvent.stopImmediatePropagation();
  }
  render() {
    return (
      <>
        <Stack direction={"row"}>
          <Stack alignItems={"center"} style={{ maxWidth: "min-content" }}>
            <Input
              inputProps={{
                "aria-labelledby": "input-slider",
                itemType: "number",
                style: { padding: 0 },
              }}
              value={this.state.gain}
              onWheel={(e) => this.onStripWheel(e)}
              onClick={(e) => this.stopPropagation(e)}
              size="small"
              sx={{ marginInline: "5px" }}
            />
            <Slider
              sx={{
                margin: "5px",
                marginBlockStart: "15px",
              }}
              color={
                (this.state.gain > 0 && this.state.gain < 12 && "warning") ||
                (this.state.gain >= 12 && "error") ||
                (this.state.gain < 0 && "info") ||
                "primary"
              }
              orientation="vertical"
              defaultValue={0.0}
              step={0.1}
              min={-60}
              max={12}
              value={this.state.gain}
              aria-label="Temperature"
              onChange={(e) => this.onGainChange(e)}
              onClick={(e) => this.onSliderClick(e)}
            />
          </Stack>
          <Stack>
            <ButtonGroup orientation="vertical" sx={{paddingInlineStart:"5px"}}>
              {[
                ...Array(this.props.physicalBuses + this.props.virtualBuses),
              ].map((_v, i) => (
                <StripBusOutput
                  key={`${i < this.props.physicalBuses ? "a" : "b"}${
                    i < this.props.physicalBuses
                      ? i
                      : i - this.props.physicalBuses
                  }`}
                  id={
                    i < this.props.physicalBuses
                      ? i
                      : i - this.props.physicalBuses
                  }
                  isVirtual={i < this.props.physicalBuses ? false : true}
                  onChange={(e) => this.onBusChange(e)}
                  default={{ enabled: this.state.outputBuses[i] }}
                />
              ))}
              <Button
                onClick={(e) => this.onMuteToggle(e)}
                variant={this.state.muted ? "contained" : "outlined"}
                color={"error"}
                size="small"
              >
                Mute
              </Button>
            </ButtonGroup>
          </Stack>
        </Stack>
      </>
    );
  }
}
