"use strict";

const React = require("react");
const classnames = require("classnames");
const syncpipe = require("syncpipe");
const splitFilterN = require("split-filter-n");
const { B } = require("../../../packages/unit-bytes-iec");
const treecutter = require("../../../packages/treecutter");

const Layout = require("../layout.jsx");

function sum(values) {
	return values.reduce((total, value) => total + value, 0);
}

function sumDriveSizes(drives) {
	return syncpipe(drives, [
		(_) => _.map((drive) => drive.size.toB().amount),
		(_) => sum(_),
		(_) => B(_)
	]);
}

function Indented({ depth, children }) {
	return (
		<div style={{ paddingLeft: depth * 10 }}>
			{children}
		</div>
	);
}

function MountEntry({ mount }) {
	return <div className="mountpoint">{mount.mountpoint}</div>;
}

function PartitionEntry({partition, isLast}) {
	function PartitionIndent({ children }) {
		return (
			<Indented depth={partition._treecutterDepth}>
				{children}
			</Indented>
		);
	}

	return (
		<tr className={classnames("partition", {last: isLast})}>
			<td>
				<PartitionIndent>
					{partition.name}
				</PartitionIndent>
			</td>
			<td>
				<PartitionIndent>
					{partition.size.toDisplay(2).toString()}
				</PartitionIndent>
			</td>
			<td colSpan={5}>
				<PartitionIndent>
					{(partition.mounts.length > 0)
						? partition.mounts.map((mount) => <MountEntry mount={mount} />)
						: <span className="notMounted">(not mounted)</span>
					}
				</PartitionIndent>
			</td>
		</tr>
	);
}

function DriveEntry({drive}) {
	let flattenedPartitions = treecutter.flatten(drive.partitions);
	let hasPartitions = (flattenedPartitions.length > 0);

	return (<>
		<tr className={classnames({hasPartitions})}>
			<td className={classnames("smart", drive.smartHealth)} rowSpan={1 + flattenedPartitions.length} />
			<td>{drive.path}</td>
			<td>{drive.size.toDisplay(2).toString()}</td>
			<td>
				{(drive.rpm != null)
					? `${drive.rpm} RPM`
					: null
				}
			</td>
			<td>{drive.serialNumber}</td>
			<td>{drive.model}</td>
			<td>{drive.modelFamily}</td>
			<td>{drive.firmwareVersion}</td>
		</tr>
		{flattenedPartitions.map((partition, i) => {
			let isLast = (i === flattenedPartitions.length - 1);

			return <PartitionEntry partition={partition} isLast={isLast} />;
		})}
	</>);
}

function TallyRow({ label, rowClass, labelClass, children }) {
	return (
		<tr className={rowClass}>
			<th colspan="2" className={labelClass}>{label}</th>
			<td>{children}</td>
			<td className="hidden" colspan="5"></td>
		</tr>
	);
}

module.exports = {
	query: {
		hardware: {
			drives: {
				path: true,
				smartHealth: true,
				size: true,
				rpm: true,
				serialNumber: true,
				model: true,
				modelFamily: true,
				firmwareVersion: true,

				blockDevice: {
					name: true
				},

				partitions: {
					$key: "allBlockDevices",
					name: true,
					size: true,

					mounts: {
						mountpoint: true
					},

					children: {
						$recurse: true,
						$recurseLimit: Infinity, // 3 by default
					}
				}
			}
		}
	},
	template: function StorageDeviceList({data}) {
		let drivesByStatus = splitFilterN(data.hardware.drives, [ "HEALTHY", "DETERIORATING", "FAILING", "UNKNOWN" ], (drive) => drive.smartHealth);

		let totalStorage = sumDriveSizes(data.hardware.drives);
		let totalHealthyStorage = sumDriveSizes(drivesByStatus.HEALTHY);
		let totalAtRiskStorage = sumDriveSizes(drivesByStatus.DETERIORATING);
		let totalFailingStorage = sumDriveSizes(drivesByStatus.FAILING);
		let totalUnknownStorage = sumDriveSizes(drivesByStatus.UNKNOWN);

		// TODO: Show unallocated space

		return (
			<Layout title="Storage Devices">
				<table className="drives">
					<tr>
						<th>SMART</th>
						<th>Device</th>
						<th>Total size</th>
						<th>RPM</th>
						<th>Serial number</th>
						<th>Model</th>
						<th>Family</th>
						<th>Firmware version</th>
					</tr>
					{data.hardware.drives.map((drive) => <DriveEntry drive={drive} />)}
					<TallyRow label="Total">
						{totalStorage.toDisplay(2).toString()}
					</TallyRow>
					<TallyRow label="Healthy" rowClass="smartStatus" labelClass="healthy">
						{totalHealthyStorage.toDisplay(2).toString()}
					</TallyRow>
					<TallyRow label="At-risk" rowClass="smartStatus" labelClass="atRisk">
						{totalAtRiskStorage.toDisplay(2).toString()}
					</TallyRow>
					<TallyRow label="Failing" rowClass="smartStatus" labelClass="failing">
						{totalFailingStorage.toDisplay(2).toString()}
					</TallyRow>
					<TallyRow label="Unknown" rowClass="smartStatus" labelClass="unknown">
						{totalUnknownStorage.toDisplay(2).toString()}
					</TallyRow>
				</table>
			</Layout>
		);
	}
};
