import { useState, type FormEvent } from "react";
import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
import * as stylex from "@stylexjs/stylex";
import { formatTime } from "@/lib/format";
import InlineError from "@/lib/InlineError";
import { groupsQuery, ruleCreateMutation, ruleDeleteMutation, rulesQuery } from "@/lib/queries";
import type { Rule, RuleAction, RuleKind } from "@/lib/types";
import { defaultGroupId } from "@/lib/defaultGroup";
import ConfirmDialog from "@/ui/ConfirmDialog";
import Select from "@/ui/Select";
import { styles as shared } from "@/ui/styles";
import { colors } from "@/ui/tokens.stylex";
import { READ_ONLY_HINT, useReadOnlyConfig } from "@/features/settings/authority";

const KIND_OPTIONS = [
	{ value: "exact", label: "exact" },
	{ value: "wildcard", label: "wildcard" },
	{ value: "regex", label: "regex" },
];

const ACTION_OPTIONS = [
	{ value: "allow", label: "allow" },
	{ value: "block", label: "block" },
];

const styles = stylex.create({
	heading: {
		fontSize: "1.5rem",
		lineHeight: "2rem",
		fontWeight: 600,
	},
	empty: {
		marginTop: "1rem",
		color: colors.textMuted,
	},
	table: {
		width: "100%",
		minWidth: "max-content",
		borderCollapse: "collapse",
		fontSize: "0.875rem",
		lineHeight: "1.25rem",
	},
	pattern: {
		fontWeight: 500,
	},
	allow: {
		color: colors.primaryOnSurface,
	},
	block: {
		color: colors.danger,
	},
	form: {
		display: "flex",
		flexDirection: "column",
		gap: "0.75rem",
		marginTop: "1.5rem",
		maxWidth: "36rem",
	},
	formHeading: {
		fontSize: "1.125rem",
		lineHeight: "1.75rem",
		fontWeight: 500,
	},
	fieldLabel: {
		display: "block",
		fontSize: "0.875rem",
		lineHeight: "1.25rem",
		fontWeight: 500,
	},
	/** One column on a phone, three from the `sm` breakpoint, as before. */
	fieldGrid: {
		display: "grid",
		gap: "0.75rem",
		gridTemplateColumns: {
			default: "repeat(1, minmax(0, 1fr))",
			"@media (min-width: 640px)": "repeat(3, minmax(0, 1fr))",
		},
	},
	submitRow: {
		display: "flex",
	},
});

export default function RulesPage() {
	const queryClient = useQueryClient();
	const { data: rules } = useSuspenseQuery(rulesQuery());
	const { data: groups } = useSuspenseQuery(groupsQuery());

	const create = useMutation(ruleCreateMutation(queryClient));
	const remove = useMutation(ruleDeleteMutation(queryClient));

	const [pattern, setPattern] = useState("");
	const [kind, setKind] = useState<RuleKind>("exact");
	const [action, setAction] = useState<RuleAction>("block");
	const [groupId, setGroupId] = useState(() => defaultGroupId(groups));
	const [pendingDelete, setPendingDelete] = useState<Rule | null>(null);
	const readOnly = useReadOnlyConfig();

	function onSubmit(event: FormEvent<HTMLFormElement>) {
		event.preventDefault();
		// A regex pattern is stored and matched byte for byte, so the UI must not
		// edit it: trimming here would make a UI-created rule differ from the same
		// bytes posted to /api/rules. Name-shaped kinds are normalized server-side,
		// so trimming them only spares a pasted space a 400.
		const sent = kind === "regex" ? pattern : pattern.trim();
		create.mutate({ group_id: groupId, pattern: sent, kind, action }, { onSuccess: () => setPattern("") });
	}

	function confirmDelete() {
		if (pendingDelete === null) return;
		remove.mutate(pendingDelete.id);
		setPendingDelete(null);
	}

	return (
		<section>
			<h1 {...stylex.props(styles.heading)}>Rules</h1>

			{rules.length === 0 ? (
				<p {...stylex.props(styles.empty)}>No allow or block rules yet. Create one below.</p>
			) : (
				<div {...stylex.props(shared.tableWrap)}>
					<table {...stylex.props(styles.table)}>
						<thead>
							<tr>
								<th {...stylex.props(shared.th)}>Pattern</th>
								<th {...stylex.props(shared.th)}>Kind</th>
								<th {...stylex.props(shared.th)}>Action</th>
								<th {...stylex.props(shared.th)}>Group</th>
								<th {...stylex.props(shared.th)}>Created</th>
								<th {...stylex.props(shared.th)}>
									<span {...stylex.props(shared.srOnly)}>Actions</span>
								</th>
							</tr>
						</thead>
						<tbody>
							{rules.map((rule) => (
								<tr key={rule.id}>
									<td {...stylex.props(shared.td, styles.pattern)}>{rule.pattern}</td>
									<td {...stylex.props(shared.td)}>{rule.kind}</td>
									<td {...stylex.props(shared.td)}>
										<span {...stylex.props(rule.action === "allow" ? styles.allow : styles.block)}>
											{rule.action}
										</span>
									</td>
									<td {...stylex.props(shared.td)}>{rule.group}</td>
									<td {...stylex.props(shared.td)}>{formatTime(rule.created_at)}</td>
									<td {...stylex.props(shared.td)}>
										<button
											type="button"
											onClick={() => setPendingDelete(rule)}
											disabled={remove.isPending || readOnly}
											title={readOnly ? READ_ONLY_HINT : undefined}
											{...stylex.props(shared.dangerLinkButton, shared.focusRing)}
										>
											Delete
										</button>
									</td>
								</tr>
							))}
						</tbody>
					</table>
				</div>
			)}
			<InlineError error={remove.error} />

			<form onSubmit={onSubmit} {...stylex.props(styles.form)}>
				<h2 {...stylex.props(styles.formHeading)}>Create rule</h2>
				<div>
					<label htmlFor="rule-pattern" {...stylex.props(styles.fieldLabel)}>
						Pattern
					</label>
					<input
						id="rule-pattern"
						type="text"
						required
						value={pattern}
						onChange={(event) => setPattern(event.target.value)}
						placeholder="ads.example.com, *.example.com or ^ad[0-9]+-"
						// A phone keyboard capitalizing the first letter is silent for
						// exact and wildcard (normalized server-side) but fatal for a
						// regex, which matches the lowercase query name byte for byte.
						autoCapitalize="none"
						autoCorrect="off"
						spellCheck={false}
						{...stylex.props(shared.input, shared.focusRing)}
					/>
				</div>
				<div {...stylex.props(styles.fieldGrid)}>
					<Select
						label="Kind"
						value={kind}
						onChange={(value) => setKind(value as RuleKind)}
						options={KIND_OPTIONS}
					/>
					<Select
						label="Action"
						value={action}
						onChange={(value) => setAction(value as RuleAction)}
						options={ACTION_OPTIONS}
					/>
					<Select
						label="Group"
						value={String(groupId)}
						onChange={(value) => setGroupId(Number(value))}
						options={groups.map((group) => ({ value: String(group.id), label: group.name }))}
					/>
				</div>
				<div {...stylex.props(styles.submitRow)}>
					<button
						type="submit"
						disabled={create.isPending || readOnly}
						title={readOnly ? READ_ONLY_HINT : undefined}
						{...stylex.props(shared.primaryButton, shared.focusRing)}
					>
						{create.isPending ? "Creating…" : "Create rule"}
					</button>
				</div>
				<InlineError error={create.error} />
			</form>

			<ConfirmDialog
				isOpen={pendingDelete !== null}
				title="Delete rule"
				message={
					pendingDelete === null
						? ""
						: `Delete the ${pendingDelete.action} rule for "${pendingDelete.pattern}"?`
				}
				confirmLabel="Delete"
				onConfirm={confirmDelete}
				onCancel={() => setPendingDelete(null)}
			/>
		</section>
	);
}
