import React, {Component} from "react";
import gql from "graphql-tag.macro";
import {graphql, withApollo, Mutation} from "react-apollo";
import {Table, Button} from "helpers/reactstrap";
import {InputField, OutputField} from "../../generic/core";
import SubscriptionHelper from "helpers/subscriptionHelper";
import SystemRow from "./systemRow";
import WingPower from "./wingPower";

const fragment = gql`
  fragment PowerData on Reactor {
    id
    type
    model
    efficiency
    displayName
    powerOutput
    hasWings
    leftWingPower
    rightWingPower
  }
`;
export const DAMAGE_REACTOR_CORE_SUB = gql`
  subscription ReactorsUpdate($simulatorId: ID!) {
    reactorUpdate(simulatorId: $simulatorId) {
      ...PowerData
    }
  }
  ${fragment}
`;

export const DAMAGE_SYSTEMS_CORE_SUB = gql`
  subscription SystemsUpdate($simulatorId: ID) {
    systemsUpdate(simulatorId: $simulatorId) {
      id
      name
      displayName
      upgraded
      wing
      power {
        power
        powerLevels
      }
      damage {
        damaged
        report
        destroyed
        which
        taskReportDamage
      }
      simulatorId
      type
    }
  }
`;

const options = [
  {key: "destroy", title: "Destroy"},
  {key: "rnd", title: "R&D"},
  {key: "engineering", title: "Engineering"},
];
class DamageControlCore extends Component {
  constructor(props) {
    super(props);
    this.state = {
      deck: null,
      room: null,
    };
  }

  setPowerOutput = output => {
    if ((!output || !parseFloat(output)) && output !== "0") return;
    const reactor = this.props.data.reactors.find(r => r.model === "reactor");
    const mutation = gql`
      mutation ReactorPowerLevel($id: ID!, $output: Int!) {
        reactorChangeOutput(id: $id, output: $output)
      }
    `;
    const variables = {
      id: reactor.id,
      output: parseInt(output, 10),
    };
    this.props.client.mutate({
      mutation,
      variables,
    });
  };
  toggleDamage = (e, system, destroyed = false, which) => {
    e.preventDefault();
    const variables = {
      systemId: system.id,
      destroyed,
      which,
    };
    let mutation;
    if (system.damage.damaged || system.damage.taskReportDamage) {
      // Fix it
      mutation = gql`
        mutation RepairSystem($systemId: ID!) {
          repairSystem(systemId: $systemId)
        }
      `;
    } else {
      // Break it
      mutation = gql`
        mutation DamageSystem(
          $systemId: ID!
          $destroyed: Boolean
          $which: String
        ) {
          damageSystem(
            systemId: $systemId
            destroyed: $destroyed
            which: $which
          )
        }
      `;
    }
    this.props.client.mutate({
      mutation,
      variables,
    });
  };
  setContext = (e, s) => {
    e.preventDefault();
    this.setState({
      context: {
        system: s,
        x: e.clientX,
        y: e.clientY,
      },
    });
    //this.toggleDamage(e, s, true)
  };

  damageOption = (e, option) => {
    const {system} = this.state.context;
    if (option === "destroy") {
      this.toggleDamage(e, system, true);
    } else {
      this.toggleDamage(e, system, false, option);
    }
    this.setState({context: null});
  };
  render() {
    if (
      this.props.data.loading ||
      !this.props.data.systems ||
      !this.props.data.reactors
    )
      return null;
    const reactor = this.props.data.reactors.find(r => r.model === "reactor");

    const systems = this.props.data.systems.concat().sort((a, b) => {
      const hasPowerA =
        a.power?.powerLevels.length > 0 &&
        (a.power?.power || a.power?.power === 0);
      const hasPowerB =
        b.power?.powerLevels.length > 0 &&
        (b.power?.power || b.power?.power === 0);

      if (hasPowerA && !hasPowerB) return -1;
      if (hasPowerB && !hasPowerA) return 1;
      if (a.type > b.type) return 1;
      if (a.type < b.type) return -1;
      if (a.name > b.name) return 1;
      if (a.name < b.name) return -1;
      return 0;
    });
    const wingedSystems = systems.reduce(
      (prev, next) => {
        if (!["left", "right"].includes(next.wing)) return prev;
        prev[next.wing].push(next);
        prev[`${next.wing}Power`] += next?.power?.power || 0;
        return prev;
      },
      {left: [], right: [], leftPower: 0, rightPower: 0},
    );
    return (
      <Mutation
        mutation={gql`
          mutation FluxPower($id: ID, $all: Boolean, $simulatorId: ID) {
            fluxSystemPower(id: $id, all: $all, simulatorId: $simulatorId)
          }
        `}
        variables={{simulatorId: this.props.simulator.id}}
      >
        {action => (
          <div onMouseLeave={() => this.setState({context: null})}>
            <Table size="sm" hover>
              <SubscriptionHelper
                subscribe={() =>
                  this.props.data.subscribeToMore({
                    document: DAMAGE_SYSTEMS_CORE_SUB,
                    variables: {
                      simulatorId: this.props.simulator.id,
                    },
                    updateQuery: (previousResult, {subscriptionData}) => {
                      return Object.assign({}, previousResult, {
                        systems: subscriptionData.data.systemsUpdate,
                      });
                    },
                  })
                }
              />
              <SubscriptionHelper
                subscribe={() =>
                  this.props.data.subscribeToMore({
                    document: DAMAGE_REACTOR_CORE_SUB,
                    variables: {
                      simulatorId: this.props.simulator.id,
                    },
                    updateQuery: (previousResult, {subscriptionData}) => {
                      return Object.assign({}, previousResult, {
                        reactors: subscriptionData.data.reactorUpdate,
                      });
                    },
                  })
                }
              />
              <thead>
                <tr>
                  <th>System</th>
                  <th>Set</th>
                  <th />
                  <th>Req</th>
                  <th title="Upgraded">U</th>
                  <th title="Flux">F</th>
                </tr>
              </thead>
              <tbody>
                {reactor?.hasWings
                  ? Object.entries(wingedSystems).map(
                      ([key, value]) =>
                        ["left", "right"].includes(key) && (
                          <WingPower
                            key={key}
                            wing={key}
                            value={value}
                            reactor={reactor}
                            wingedSystems={wingedSystems}
                            simulatorId={this.props.simulator.id}
                            fluxPower={id => action({variables: {id}})}
                            toggleDamage={this.toggleDamage}
                            setContext={this.setContext}
                          />
                        ),
                    )
                  : systems.map(s => (
                      <SystemRow
                        key={s.id}
                        simulatorId={this.props.simulator.id}
                        fluxPower={id => action({variables: {id}})}
                        toggleDamage={this.toggleDamage}
                        s={s}
                        setContext={this.setContext}
                      />
                    ))}
                <tr>
                  <td>Total</td>
                  <td>
                    <OutputField
                      alert={
                        reactor &&
                        Math.round(reactor.powerOutput * reactor.efficiency) <
                          this.props.data.systems.reduce(
                            (prev, next) =>
                              next.power ? prev + next.power.power : prev,
                            0,
                          )
                      }
                    >
                      {this.props.data.systems.reduce(
                        (prev, next) =>
                          next.power ? prev + next.power.power : prev,
                        0,
                      )}
                    </OutputField>
                  </td>
                  <td>{reactor && "/"}</td>
                  <td>
                    {reactor && (
                      <OutputField title="Reactor Output">
                        {Math.round(reactor.powerOutput * reactor.efficiency)}
                      </OutputField>
                    )}
                  </td>
                  <td>
                    {reactor && (
                      <InputField
                        title="Reactor Power Level"
                        prompt="What is the new power output?"
                        onClick={this.setPowerOutput}
                      >
                        {reactor.powerOutput}
                      </InputField>
                    )}
                  </td>
                  <td />
                </tr>
                <tr>
                  <td colSpan={6}>Right-Click for options</td>
                </tr>
                <tr>
                  <td colSpan={1}>
                    <Button block size="sm" color="warning" onClick={action}>
                      Flux Random
                    </Button>
                  </td>
                  <td colSpan={5}>
                    <Button
                      block
                      size="sm"
                      color="danger"
                      onClick={() =>
                        action({
                          variables: {
                            all: true,
                            simulatorId: this.props.simulator.id,
                          },
                        })
                      }
                    >
                      Flux All
                    </Button>
                  </td>
                </tr>
              </tbody>
            </Table>
            {this.state.context && (
              <div
                style={{
                  transform: `translate(${this.state.context.x}px, ${this.state.context.y}px)`,
                }}
                className="systems-context"
              >
                {options.map(o => (
                  <p key={o.key} onClick={e => this.damageOption(e, o.key)}>
                    {o.title}
                  </p>
                ))}
              </div>
            )}
          </div>
        )}
      </Mutation>
    );
  }
}
export const DAMAGE_SYSTEMS_CORE_QUERY = gql`
  query Systems($simulatorId: ID) {
    reactors(simulatorId: $simulatorId) {
      ...PowerData
    }
    systems(simulatorId: $simulatorId) {
      id
      name
      displayName
      upgraded
      wing
      power {
        power
        powerLevels
      }
      damage {
        damaged
        report
        destroyed
        which
        taskReportDamage
      }
      simulatorId
      type
    }
  }
  ${fragment}
`;

export default graphql(DAMAGE_SYSTEMS_CORE_QUERY, {
  options: ownProps => ({
    fetchPolicy: "cache-and-network",
    variables: {simulatorId: ownProps.simulator.id},
  }),
})(withApollo(DamageControlCore));
