import { useQuery } from "@apollo/client";
import { Button, Card, Col, Result, Row, Select, Space } from "antd";
import queryString from "query-string";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import SocketIO from "socket.io-client";
import AlertComponent from "../../components/alert/alert.component";
import DmsAllocationsSummary from "../../components/dms-allocations-summary/dms-allocations-summary.component";
import DmsCustomerSelector from "../../components/dms-customer-selector/dms-customer-selector.component";
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
import { auth } from "../../firebase/firebase.utils";
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
import { insertAuditTrail, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop
});

const mapDispatchToProps = (dispatch) => ({
  setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
  setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
  insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
});

export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);

export const socket = SocketIO(
  import.meta.env.PROD ? import.meta.env.VITE_APP_AXIOS_BASE_API_URL : "", // for dev testing,
  {
    path: "/ws",
    withCredentials: true,
    auth: async (callback) => {
      const token = auth.currentUser && (await auth.currentUser.getIdToken());
      callback({ token });
    }
  }
);

export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, insertAuditTrail }) {
  const { t } = useTranslation();
  const [logLevel, setLogLevel] = useState(determineDmsType(bodyshop) === "pbs" ? "INFO" : "DEBUG");
  const history = useNavigate();
  const [logs, setLogs] = useState([]);
  const search = queryString.parse(useLocation().search);
  const { jobId } = search;
  const notification = useNotification();

  const { loading, error, data } = useQuery(QUERY_JOB_EXPORT_DMS, {
    variables: { id: jobId },
    skip: !jobId,
    fetchPolicy: "network-only",
    nextFetchPolicy: "network-only"
  });
  const logsRef = useRef(null);

  useEffect(() => {
    document.title = t("titles.dms", {
      app: InstanceRenderManager({
        imex: "$t(titles.imexonline)",
        rome: "$t(titles.romeonline)"
      })
    });
    setSelectedHeader("dms");
    setBreadcrumbs([
      {
        link: "/manage/accounting/receivables",
        label: t("titles.bc.accounting-receivables")
      },
      {
        link: "/manage/dms",
        label: t("titles.bc.dms")
      }
    ]);
  }, [t, setBreadcrumbs, setSelectedHeader]);

  useEffect(() => {
    socket.on("connect", () => socket.emit("set-log-level", logLevel));
    socket.on("reconnect", () => {
      setLogs((logs) => {
        return [
          ...logs,
          {
            timestamp: new Date(),
            level: "warn",
            message: "Reconnected to CDK Export Service"
          }
        ];
      });
    });
    socket.on("connect_error", (err) => {
      console.log(`connect_error due to ${err}`, err);
      notification.error({ message: err.message });
    });
    socket.on("log-event", (payload) => {
      setLogs((logs) => {
        return [...logs, payload];
      });
    });
    socket.on("export-success", (payload) => {
      notification.success({
        message: t("jobs.successes.exported")
      });
      insertAuditTrail({
        jobid: payload,
        operation: AuditTrailMapping.jobexported(),
        type: "jobexported"
      });
      history("/manage/accounting/receivables");
    });

    if (socket.disconnected) socket.connect();
    return () => {
      socket.removeAllListeners();
      socket.disconnect();
    };
  }, []);

  if (loading) return <LoadingSpinner />;
  if (error) return <AlertComponent message={error.message} type="error" />;

  if (!jobId || !(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) || !(data && data.jobs_by_pk))
    return <Result status="404" title={t("general.errors.notfound")} />;

  if (data.jobs_by_pk && data.jobs_by_pk.date_exported)
    return <Result status="warning" title={t("dms.errors.alreadyexported")} />;

  return (
    <div>
      <Row gutter={[16, 16]}>
        <Col md={24} lg={10}>
          <DmsAllocationsSummary
            title={
              <span>
                <Link to={`/manage/jobs/${data && data.jobs_by_pk.id}`}>{`${
                  data && data.jobs_by_pk && data.jobs_by_pk.ro_number
                }`}</Link>
                {` | ${OwnerNameDisplayFunction(data.jobs_by_pk)} | ${
                  data.jobs_by_pk.v_model_yr || ""
                } ${data.jobs_by_pk.v_make_desc || ""} ${data.jobs_by_pk.v_model_desc || ""}`}
              </span>
            }
            socket={socket}
            jobId={jobId}
          />
        </Col>
        <Col md={24} lg={14}>
          <DmsPostForm socket={socket} jobId={jobId} job={data && data.jobs_by_pk} logsRef={logsRef} />
        </Col>

        <DmsCustomerSelector />

        <Col span={24}>
          <div ref={logsRef}>
            <Card
              title={t("jobs.labels.dms.logs")}
              extra={
                <Space wrap>
                  <Select
                    placeholder="Log Level"
                    value={logLevel}
                    onChange={(value) => {
                      setLogLevel(value);
                      socket.emit("set-log-level", value);
                    }}
                  >
                    <Select.Option key="DEBUG">DEBUG</Select.Option>
                    <Select.Option key="INFO">INFO</Select.Option>
                    <Select.Option key="WARN">WARN</Select.Option>
                    <Select.Option key="ERROR">ERROR</Select.Option>
                  </Select>
                  <Button onClick={() => setLogs([])}>Clear Logs</Button>
                  <Button
                    onClick={() => {
                      setLogs([]);
                      socket.disconnect();
                      socket.connect();
                    }}
                  >
                    Reconnect
                  </Button>
                </Space>
              }
            >
              <DmsLogEvents socket={socket} logs={logs} />
            </Card>
          </div>
        </Col>
      </Row>
    </div>
  );
}

export const determineDmsType = (bodyshop) => {
  if (bodyshop.cdk_dealerid) return "cdk";
  else {
    return "pbs";
  }
};
