// Copyright 2023 Northern.tech AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { Button, Table, TableBody, TableCell, TableHead, TableRow, buttonClasses, tableCellClasses } from '@mui/material';
import { makeStyles } from 'tss-react/mui';

import Confirm from '@northern.tech/common-ui/Confirm';
import { ContentSection } from '@northern.tech/common-ui/ContentSection';
import InfoHint from '@northern.tech/common-ui/InfoHint';
import { Link } from '@northern.tech/common-ui/Link';
import Pagination from '@northern.tech/common-ui/Pagination';
import { MaybeTime } from '@northern.tech/common-ui/Time';
import { getToken } from '@northern.tech/store/auth';
import { DEVICE_LIST_DEFAULTS, deploymentStatesToSubstates } from '@northern.tech/store/constants';
import { generateReleasesPath } from '@northern.tech/store/locationutils';
import { getDeploymentById as getDeploymentByIdSelector, getFeatures, getIsPreview } from '@northern.tech/store/selectors';
import { getDeviceDeployments, getDeviceLog, getSingleDeployment, resetDeviceDeployments } from '@northern.tech/store/thunks';
import { isDarkMode } from '@northern.tech/store/utils';

import LogDialog from '../../deployments/deployment-report/Log';
import { HELPTOOLTIPS } from '../../helptips/HelpTooltips';
import { MenderHelpTooltip } from '../../helptips/MenderTooltip';
import { DeviceStateSelection } from '../widgets/DeviceStateSelection';

const useStyles = makeStyles()(theme => ({
  deletion: { justifyContent: 'flex-end' },
  selection: {
    fontSize: 13,
    marginLeft: theme.spacing(0.5),
    marginTop: 2
  },
  table: {
    minHeight: '10vh',
    [`.deleted > .${tableCellClasses.root}, .deleted a`]: {
      background: isDarkMode(theme.palette.mode) ? theme.palette.info.dark : theme.palette.info.light,
      color: theme.palette.grey[700],
      [`.${buttonClasses.root}`]: { color: theme.palette.text.primary }
    }
  }
}));

const EmptyState = ({ isFiltered }) => (
  <>
    <div className="flexbox column centered margin-large">
      <p className="align-center muted">
        No deployments were found.
        <br />
        {isFiltered && <>Try adjusting the filters</>}
      </p>
    </div>
    <InfoHint content="If this device is part of a pending or scheduled deployment, the deployment will only appear here once it has started and the device has reported its update status to the server." />
  </>
);

const columns = [
  {
    content: 'Release',
    key: 'release',
    Component: ({ deviceDeployment: { release } }) => <Link to={generateReleasesPath({ pageState: { selectedRelease: release } })}>{release}</Link>
  },
  { content: 'Started', key: 'created', Component: ({ deviceDeployment: { created } }) => <MaybeTime value={created} /> },
  { content: 'Finished', key: 'finished', Component: ({ deviceDeployment: { finished } }) => <MaybeTime value={finished} /> },
  { content: 'Device status', key: 'status', Component: ({ deviceDeployment: { status } }) => status },
  {
    content: '',
    key: 'log',
    Component: ({ deviceDeployment: { id, log }, onLogClick }) => log && <Button onClick={() => onLogClick(id)}>Log</Button>
  },
  {
    content: '',
    key: 'target',
    Component: ({ deviceDeployment: { id, route } }) => <Link to={`/deployments/${route}?id=${id}&open=true`}>View deployment</Link>
  }
];

const History = ({ className, items, onLogClick, page, perPage, setPage, setPerPage, total }) => {
  const token = getToken();
  const onChangeRowsPerPage = perPage => {
    setPage(1);
    setPerPage(perPage);
  };
  const wasReset = items.reduce((accu, { deleted }) => {
    if (!accu) {
      return !!deleted;
    }
    return accu;
  }, false);
  return (
    <div className={className}>
      <Table>
        <TableHead>
          <TableRow>
            {columns.map(({ content, key }) => (
              <TableCell key={key}>{content}</TableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          {items.map(item => (
            <TableRow className={item.deleted ? 'deleted' : ''} key={item.id}>
              {columns.map(({ key, Component }) => (
                <TableCell key={`${item.id}-${key}`}>
                  <Component token={token} deviceDeployment={item} onLogClick={onLogClick} />
                </TableCell>
              ))}
            </TableRow>
          ))}
        </TableBody>
      </Table>
      <div className="flexbox align-items-center space-between">
        <Pagination
          count={total}
          onChangePage={setPage}
          onChangeRowsPerPage={onChangeRowsPerPage}
          page={page}
          rowsPerPage={perPage}
          rowsPerPageOptions={[10, 20]}
        />
        {wasReset && <MenderHelpTooltip className="margin-top margin-bottom-none" id={HELPTOOLTIPS.resetHistory.id} />}
      </div>
    </div>
  );
};

const deploymentStates = {
  any: { key: 'any', title: () => 'any', values: [] },
  pending: { key: 'pending', title: () => 'pending', values: deploymentStatesToSubstates.pending },
  inprogress: { key: 'inprogress', title: () => 'in progress', values: deploymentStatesToSubstates.inprogress },
  paused: { key: 'paused', title: () => 'paused', values: deploymentStatesToSubstates.paused },
  failures: { key: 'failures', title: () => 'failures', values: deploymentStatesToSubstates.failures },
  successes: { key: 'successes', title: () => 'successes', values: deploymentStatesToSubstates.successes }
};

export const Deployments = ({ device }) => {
  const [filters, setFilters] = useState([deploymentStates.any.key]);
  const [page, setPage] = useState(DEVICE_LIST_DEFAULTS.page);
  const [perPage, setPerPage] = useState(10);
  const [isChecking, setIsChecking] = useState(false);
  const [showsDeploymentLogForId, setShowsDeploymentLogForId] = useState('');
  const { classes } = useStyles();
  const { hasAiEnabled, isHosted } = useSelector(getFeatures);
  const isPreview = useSelector(getIsPreview);
  const canAi = isHosted && (isPreview || hasAiEnabled);
  const dispatch = useDispatch();
  const deployment = useSelector(state => getDeploymentByIdSelector(state, showsDeploymentLogForId));

  useEffect(() => {
    if (!device?.id) {
      return;
    }
    const filterSelection = deploymentStates[filters[0]].values;
    dispatch(getDeviceDeployments({ deviceId: device.id, filterSelection, page, perPage }));
  }, [device.id, dispatch, filters, page, perPage]);

  useEffect(() => {
    if (!showsDeploymentLogForId) {
      return;
    }
    dispatch(getDeviceLog({ deploymentId: showsDeploymentLogForId, deviceId: device.id }));
    dispatch(getSingleDeployment(showsDeploymentLogForId));
  }, [device.id, dispatch, showsDeploymentLogForId]);

  const onSelectStatus = status => setFilters([status]);

  const onResetStart = () => setIsChecking(true);

  const onResetConfirm = () => dispatch(resetDeviceDeployments(device.id)).then(() => setIsChecking(false));

  const { deviceDeployments = [], deploymentsCount } = device;

  return (
    <ContentSection className="margin-bottom" title="Deployments">
      <div className="flexbox">
        <DeviceStateSelection className={classes.selection} onStateChange={onSelectStatus} selectedState={filters[0]} states={deploymentStates} />
      </div>

      {!deviceDeployments.length ? (
        <EmptyState isFiltered={filters[0] !== deploymentStates.any.key} />
      ) : (
        <>
          <History
            className={classes.table}
            items={deviceDeployments}
            onLogClick={setShowsDeploymentLogForId}
            page={page}
            perPage={perPage}
            setPage={setPage}
            setPerPage={setPerPage}
            total={deploymentsCount}
          />
          <div className={`flexbox margin-top relative ${classes.deletion}`}>
            {isChecking && (
              <Confirm
                classes="confirmation-overlay"
                cancel={() => setIsChecking(false)}
                action={onResetConfirm}
                message="This will reset the stored device deployment history for this device. Are you sure?"
                style={{ marginRight: 0 }}
              />
            )}
            <Button onClick={onResetStart} variant="contained">
              Reset device deployment history
            </Button>
          </div>
        </>
      )}
      {showsDeploymentLogForId && deployment && (
        <LogDialog canAi={canAi} deployment={deployment} deviceId={device.id} onClose={() => setShowsDeploymentLogForId('')} />
      )}
    </ContentSection>
  );
};

export default Deployments;
