import { Form, Head, Link } from '@inertiajs/react';
import SensorController from '@/actions/App/Http/Controllers/Admin/SensorController';
import SensorHistoryController from '@/actions/App/Http/Controllers/SensorHistoryController';
import SensorTypeController from '@/actions/App/Http/Controllers/Admin/SensorTypeController';
import Heading from '@/components/heading';
import InputError from '@/components/input-error';
import { formatSensorMetricValue } from '@/lib/sensor-metrics';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
    Card,
    CardContent,
    CardDescription,
    CardHeader,
    CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';

type SensorType = {
    id: number;
    name: string;
    description: string | null;
    device_id_pattern: string;
    created_at: string | null;
};

type ObservedDevice = {
    id: number;
    device_id: string | null;
    sensor_type_id: number | null;
    sensor_type_name: string | null;
    decoded_payload: Record<string, unknown>;
    created_at: string | null;
};

type Sensor = {
    id: number;
    name: string;
    friendly_name: string | null;
    display_name: string;
    sensor_type_id: number;
    department_id: number | null;
    department_name: string | null;
    device_id: string;
    description: string | null;
    image_url: string | null;
    latitude: number | null;
    longitude: number | null;
    sensor_type_name: string | null;
    latest_data: Record<string, unknown>;
    latest_received_at: string | null;
};

type Department = {
    id: number;
    name: string;
};

export default function SensorTypes({
    sensorTypes,
    observedDevices,
    sensors,
    departments,
    canManageSensorTypes,
}: {
    sensorTypes: SensorType[];
    observedDevices: ObservedDevice[];
    sensors: Sensor[];
    departments: Department[];
    canManageSensorTypes: boolean;
}) {
    return (
        <>
            <Head title="Sensor types" />

            <div className="space-y-6 p-4">
                <Heading
                    title="Sensor types"
                    description="Create sensor types that match incoming device IDs using wildcard patterns like weather-*."
                />

                <div className="grid gap-6 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,1.9fr)]">
                    {canManageSensorTypes ? (
                        <Card>
                            <CardHeader>
                                <CardTitle>Add sensor type</CardTitle>
                                <CardDescription>
                                    Sensor types now use the decoded payload already sent by the
                                    webhook source.
                                </CardDescription>
                            </CardHeader>
                            <CardContent>
                                <Form
                                    {...SensorTypeController.store.form()}
                                    resetOnSuccess={['name', 'description', 'device_id_pattern']}
                                    className="space-y-4"
                                >
                                    {({ processing, errors }) => (
                                        <>
                                            <div className="grid gap-2">
                                                <Label htmlFor="name">Name</Label>
                                                <Input
                                                    id="name"
                                                    name="name"
                                                    placeholder="Weather station"
                                                    required
                                                />
                                                <InputError message={errors.name} />
                                            </div>

                                            <div className="grid gap-2">
                                                <Label htmlFor="device_id_pattern">
                                                    Device ID pattern
                                                </Label>
                                                <Input
                                                    id="device_id_pattern"
                                                    name="device_id_pattern"
                                                    placeholder="weather-*"
                                                    required
                                                />
                                                <p className="text-xs text-muted-foreground">
                                                    Uses wildcard matching against The Things Stack
                                                    device IDs.
                                                </p>
                                                <InputError
                                                    message={errors.device_id_pattern}
                                                />
                                            </div>

                                            <div className="grid gap-2">
                                                <Label htmlFor="description">Description</Label>
                                                <textarea
                                                    id="description"
                                                    name="description"
                                                    placeholder="Milesight WTS506 outdoor weather station"
                                                    className="min-h-24 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
                                                />
                                                <InputError message={errors.description} />
                                            </div>

                                            <Button
                                                type="submit"
                                                disabled={processing}
                                                className="w-full"
                                            >
                                                Save sensor type
                                            </Button>
                                        </>
                                    )}
                                </Form>
                            </CardContent>
                        </Card>
                    ) : (
                        <Card>
                            <CardHeader>
                                <CardTitle>Department sensors</CardTitle>
                                <CardDescription>
                                    You can register devices and manage sensors inside the
                                    departments assigned to you.
                                </CardDescription>
                            </CardHeader>
                            <CardContent className="text-sm text-muted-foreground">
                                Sensor types are managed by the main admin. You can still assign
                                observed devices to departments and update the sensors you manage.
                            </CardContent>
                        </Card>
                    )}

                    <Card>
                        <CardHeader>
                            <CardTitle>Registered sensor types</CardTitle>
                            <CardDescription>
                                Device match rules used to associate incoming webhook payloads with
                                sensors.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-3">
                            {sensorTypes.length === 0 ? (
                                <div className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground">
                                    No sensor types have been created yet.
                                </div>
                            ) : (
                                sensorTypes.map((sensorType) => (
                                    <article key={sensorType.id} className="rounded-lg border p-4">
                                        <div className="space-y-1">
                                            <h2 className="font-medium">{sensorType.name}</h2>
                                            <p className="text-sm text-muted-foreground">
                                                {sensorType.description ?? 'No description provided.'}
                                            </p>
                                            <p className="text-xs text-muted-foreground">
                                                Added {sensorType.created_at ?? 'recently'}
                                            </p>
                                        </div>

                                        <div className="mt-4 rounded-lg bg-muted p-3 text-sm">
                                            Matches device IDs: {sensorType.device_id_pattern}
                                        </div>
                                    </article>
                                ))
                            )}
                        </CardContent>
                    </Card>
                </div>

                <div className="grid gap-6 xl:grid-cols-2">
                    <Card>
                        <CardHeader>
                            <CardTitle>Observed sensor data</CardTitle>
                            <CardDescription>
                                Create sensors from the latest decoded payload received for each
                                device.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            {observedDevices.length === 0 ? (
                                <div className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground">
                                    No unregistered device data is available yet.
                                </div>
                            ) : (
                                observedDevices.map((device) => (
                                    <article key={device.id} className="rounded-xl border p-4">
                                        <div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
                                            <div className="space-y-1">
                                                <h2 className="font-medium">
                                                    {device.device_id ?? 'Unknown device'}
                                                </h2>
                                                <p className="text-xs text-muted-foreground">
                                                    Latest reading {device.created_at ?? 'recently'}
                                                </p>
                                            </div>

                                            {device.sensor_type_name ? (
                                                <Badge variant="secondary">
                                                    {device.sensor_type_name}
                                                </Badge>
                                            ) : (
                                                <Badge variant="outline">No sensor type</Badge>
                                            )}
                                        </div>

                                        <div className="mt-4 grid gap-3 sm:grid-cols-2">
                                            {Object.entries(device.decoded_payload).length === 0 ? (
                                                <div className="rounded-lg border border-dashed p-4 text-sm text-muted-foreground sm:col-span-2">
                                                    No decoded values were stored for this device.
                                                </div>
                                            ) : (
                                                Object.entries(device.decoded_payload).map(
                                                    ([key, value]) => (
                                                        <div key={key} className="rounded-lg bg-muted p-4">
                                                            <div className="text-xs uppercase tracking-wide text-muted-foreground">
                                                                {key.replaceAll('_', ' ')}
                                                            </div>
                                                            <div className="mt-2 text-lg font-semibold">
                                                                {typeof value === 'object'
                                                                    ? JSON.stringify(value)
                                                                    : formatSensorMetricValue(
                                                                          key,
                                                                          value,
                                                                      )}
                                                            </div>
                                                        </div>
                                                    ),
                                                )
                                            )}
                                        </div>

                                        {device.device_id && device.sensor_type_id ? (
                                            <Form
                                                {...SensorController.store.form()}
                                                encType="multipart/form-data"
                                                className="mt-4 space-y-3"
                                            >
                                                {({ processing, errors }) => (
                                                    <>
                                                        <input
                                                            type="hidden"
                                                            name="device_id"
                                                            value={device.device_id}
                                                        />
                                                        <input
                                                            type="hidden"
                                                            name="sensor_type_id"
                                                            value={device.sensor_type_id}
                                                        />

                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`department-${device.id}`}>
                                                                Department
                                                            </Label>
                                                            <select
                                                                id={`department-${device.id}`}
                                                                name="department_id"
                                                                defaultValue={
                                                                    departments[0]?.id ?? ''
                                                                }
                                                                className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
                                                                required
                                                            >
                                                                {departments.map((department) => (
                                                                    <option
                                                                        key={department.id}
                                                                        value={department.id}
                                                                    >
                                                                        {department.name}
                                                                    </option>
                                                                ))}
                                                            </select>
                                                            <InputError
                                                                message={errors.department_id}
                                                            />
                                                        </div>

                                                        <div className="grid gap-3 md:grid-cols-2">
                                                            <div className="grid gap-2">
                                                                <Label htmlFor={`name-${device.id}`}>
                                                                    Internal name
                                                                </Label>
                                                                <Input
                                                                    id={`name-${device.id}`}
                                                                    name="name"
                                                                    defaultValue={device.device_id}
                                                                    required
                                                                />
                                                                <InputError message={errors.name} />
                                                            </div>

                                                            <div className="grid gap-2">
                                                                <Label htmlFor={`friendly-name-${device.id}`}>
                                                                    Friendly name
                                                                </Label>
                                                                <Input
                                                                    id={`friendly-name-${device.id}`}
                                                                    name="friendly_name"
                                                                    placeholder="Yard weather station"
                                                                />
                                                                <InputError
                                                                    message={errors.friendly_name}
                                                                />
                                                            </div>
                                                        </div>

                                                        <div className="grid gap-3 md:grid-cols-1">
                                                            <div className="grid gap-2">
                                                                <Label htmlFor={`description-${device.id}`}>
                                                                    Description
                                                                </Label>
                                                                <Input
                                                                    id={`description-${device.id}`}
                                                                    name="description"
                                                                    placeholder="Mounted location or notes"
                                                                />
                                                                <InputError
                                                                    message={errors.description}
                                                                />
                                                            </div>
                                                        </div>

                                                        <div className="grid gap-3 md:grid-cols-2">
                                                            <div className="grid gap-2">
                                                                <Label htmlFor={`latitude-${device.id}`}>
                                                                    Latitude
                                                                </Label>
                                                                <Input
                                                                    id={`latitude-${device.id}`}
                                                                    name="latitude"
                                                                    type="number"
                                                                    step="any"
                                                                    placeholder="40.7128"
                                                                />
                                                                <InputError message={errors.latitude} />
                                                            </div>

                                                            <div className="grid gap-2">
                                                                <Label htmlFor={`longitude-${device.id}`}>
                                                                    Longitude
                                                                </Label>
                                                                <Input
                                                                    id={`longitude-${device.id}`}
                                                                    name="longitude"
                                                                    type="number"
                                                                    step="any"
                                                                    placeholder="-74.0060"
                                                                />
                                                                <InputError
                                                                    message={errors.longitude}
                                                                />
                                                            </div>
                                                        </div>

                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`image-${device.id}`}>
                                                                Sensor image
                                                            </Label>
                                                            <Input
                                                                id={`image-${device.id}`}
                                                                name="image"
                                                                type="file"
                                                                accept="image/png,image/jpeg,image/webp"
                                                            />
                                                            <InputError message={errors.image} />
                                                        </div>

                                                        <InputError message={errors.device_id} />
                                                        <InputError message={errors.sensor_type_id} />

                                                        <Button
                                                            type="submit"
                                                            disabled={
                                                                processing ||
                                                                departments.length === 0
                                                            }
                                                        >
                                                            Create sensor
                                                        </Button>
                                                    </>
                                                )}
                                            </Form>
                                        ) : (
                                            <div className="mt-4 rounded-lg border border-dashed p-4 text-sm text-muted-foreground">
                                                This device needs a matching sensor type before it can
                                                be registered as a sensor.
                                            </div>
                                        )}
                                    </article>
                                ))
                            )}
                        </CardContent>
                    </Card>

                    <Card>
                        <CardHeader>
                            <CardTitle>Registered sensors</CardTitle>
                            <CardDescription>
                                Sensors created from observed device data, with their latest stored
                                readings.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            {sensors.length === 0 ? (
                                <div className="rounded-lg border border-dashed p-6 text-sm text-muted-foreground">
                                    No sensors have been created yet.
                                </div>
                            ) : (
                                sensors.map((sensor) => (
                                    <article key={sensor.id} className="rounded-xl border p-4">
                                        <div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
                                            <div className="space-y-1">
                                                <h2 className="font-medium">{sensor.display_name}</h2>
                                                {sensor.friendly_name ? (
                                                    <p className="text-xs text-muted-foreground">
                                                        Internal name: {sensor.name}
                                                    </p>
                                                ) : null}
                                                <p className="text-sm text-muted-foreground">
                                                    {sensor.description ?? 'No description provided.'}
                                                </p>
                                                <p className="text-xs text-muted-foreground">
                                                    Device ID: {sensor.device_id}
                                                </p>
                                                <p className="text-xs text-muted-foreground">
                                                    Coordinates:{' '}
                                                    {sensor.latitude !== null &&
                                                    sensor.longitude !== null
                                                        ? `${sensor.latitude.toFixed(4)}, ${sensor.longitude.toFixed(4)}`
                                                        : 'Not set'}
                                                </p>
                                                <p className="text-xs text-muted-foreground">
                                                    Last update:{' '}
                                                    {sensor.latest_received_at ?? 'No readings yet'}
                                                </p>
                                            </div>

                                            {sensor.sensor_type_name ? (
                                                <div className="flex flex-wrap gap-2">
                                                    <Badge variant="secondary">
                                                        {sensor.sensor_type_name}
                                                    </Badge>
                                                    {sensor.department_name ? (
                                                        <Badge variant="outline">
                                                            {sensor.department_name}
                                                        </Badge>
                                                    ) : null}
                                                </div>
                                            ) : sensor.department_name ? (
                                                <Badge variant="outline">
                                                    {sensor.department_name}
                                                </Badge>
                                            ) : null}
                                        </div>

                                        {sensor.image_url ? (
                                            <div className="mt-4 overflow-hidden rounded-xl border">
                                                <img
                                                    src={sensor.image_url}
                                                    alt={sensor.display_name}
                                                    className="h-40 w-full object-cover"
                                                />
                                            </div>
                                        ) : null}

                                        <div className="mt-4 grid gap-3 sm:grid-cols-2">
                                            {Object.entries(sensor.latest_data).length === 0 ? (
                                                <div className="rounded-lg border border-dashed p-4 text-sm text-muted-foreground sm:col-span-2">
                                                    No decoded values are stored for this sensor yet.
                                                </div>
                                            ) : (
                                                Object.entries(sensor.latest_data).map(
                                                    ([key, value]) => (
                                                        <div key={key} className="rounded-lg bg-muted p-4">
                                                            <div className="text-xs uppercase tracking-wide text-muted-foreground">
                                                                {key.replaceAll('_', ' ')}
                                                            </div>
                                                            <div className="mt-2 text-lg font-semibold">
                                                                {typeof value === 'object'
                                                                    ? JSON.stringify(value)
                                                                    : formatSensorMetricValue(
                                                                          key,
                                                                          value,
                                                                      )}
                                                            </div>
                                                        </div>
                                                    ),
                                                )
                                            )}
                                        </div>

                                        <Form
                                            {...SensorController.update.form(sensor.id)}
                                            encType="multipart/form-data"
                                            className="mt-4 space-y-3 border-t pt-4"
                                        >
                                            {({ processing, errors }) => (
                                                <>
                                                    <input
                                                        type="hidden"
                                                        name="sensor_type_id"
                                                        value={sensor.sensor_type_id}
                                                    />

                                                    <div className="grid gap-2 md:max-w-xs">
                                                        <Label
                                                            htmlFor={`edit-department-${sensor.id}`}
                                                        >
                                                            Department
                                                        </Label>
                                                        <select
                                                            id={`edit-department-${sensor.id}`}
                                                            name="department_id"
                                                            defaultValue={
                                                                sensor.department_id ?? ''
                                                            }
                                                            className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]"
                                                            required
                                                        >
                                                            {departments.map((department) => (
                                                                <option
                                                                    key={department.id}
                                                                    value={department.id}
                                                                >
                                                                    {department.name}
                                                                </option>
                                                            ))}
                                                        </select>
                                                        <InputError
                                                            message={errors.department_id}
                                                        />
                                                    </div>

                                                    <div className="grid gap-3 md:grid-cols-2">
                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`edit-name-${sensor.id}`}>
                                                                Internal name
                                                            </Label>
                                                            <Input
                                                                id={`edit-name-${sensor.id}`}
                                                                name="name"
                                                                defaultValue={sensor.name}
                                                                required
                                                            />
                                                            <InputError message={errors.name} />
                                                        </div>

                                                        <div className="grid gap-2">
                                                            <Label
                                                                htmlFor={`edit-friendly-name-${sensor.id}`}
                                                            >
                                                                Friendly name
                                                            </Label>
                                                            <Input
                                                                id={`edit-friendly-name-${sensor.id}`}
                                                                name="friendly_name"
                                                                defaultValue={
                                                                    sensor.friendly_name ?? ''
                                                                }
                                                                placeholder="Shown on dashboard"
                                                            />
                                                            <InputError
                                                                message={errors.friendly_name}
                                                            />
                                                        </div>
                                                    </div>

                                                    <div className="grid gap-3 md:grid-cols-2">
                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`edit-device-id-${sensor.id}`}>
                                                                Device ID
                                                            </Label>
                                                            <Input
                                                                id={`edit-device-id-${sensor.id}`}
                                                                name="device_id"
                                                                defaultValue={sensor.device_id}
                                                                required
                                                            />
                                                            <InputError message={errors.device_id} />
                                                        </div>

                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`edit-description-${sensor.id}`}>
                                                                Description
                                                            </Label>
                                                            <Input
                                                                id={`edit-description-${sensor.id}`}
                                                                name="description"
                                                                defaultValue={sensor.description ?? ''}
                                                                placeholder="Mounted location or notes"
                                                            />
                                                            <InputError
                                                                message={errors.description}
                                                            />
                                                        </div>
                                                    </div>

                                                    <div className="grid gap-3 md:grid-cols-2">
                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`edit-latitude-${sensor.id}`}>
                                                                Latitude
                                                            </Label>
                                                            <Input
                                                                id={`edit-latitude-${sensor.id}`}
                                                                name="latitude"
                                                                type="number"
                                                                step="any"
                                                                defaultValue={sensor.latitude ?? ''}
                                                            />
                                                            <InputError message={errors.latitude} />
                                                        </div>

                                                        <div className="grid gap-2">
                                                            <Label htmlFor={`edit-longitude-${sensor.id}`}>
                                                                Longitude
                                                            </Label>
                                                            <Input
                                                                id={`edit-longitude-${sensor.id}`}
                                                                name="longitude"
                                                                type="number"
                                                                step="any"
                                                                defaultValue={sensor.longitude ?? ''}
                                                            />
                                                            <InputError message={errors.longitude} />
                                                        </div>
                                                    </div>

                                                    <div className="grid gap-2">
                                                        <Label htmlFor={`edit-image-${sensor.id}`}>
                                                            Replace image
                                                        </Label>
                                                        <Input
                                                            id={`edit-image-${sensor.id}`}
                                                            name="image"
                                                            type="file"
                                                            accept="image/png,image/jpeg,image/webp"
                                                        />
                                                        <InputError message={errors.image} />
                                                    </div>

                                                    <InputError message={errors.sensor_type_id} />

                                                    <Button type="submit" disabled={processing}>
                                                        Save changes
                                                    </Button>
                                                </>
                                            )}
                                        </Form>

                                        <div className="mt-3">
                                            <Button variant="outline" asChild>
                                                <Link href={SensorHistoryController(sensor.id)}>
                                                    View history
                                                </Link>
                                            </Button>
                                        </div>
                                    </article>
                                ))
                            )}
                        </CardContent>
                    </Card>
                </div>
            </div>
        </>
    );
}

SensorTypes.layout = {
    breadcrumbs: [
        {
            title: 'Sensor types',
            href: SensorTypeController.index(),
        },
    ],
};
