<script setup lang="ts">
import SpecRow from "@/components/environments/SpecRow.vue";
import TopologyCard from "@/components/environments/TopologyCard.vue";
import InputError from "@/components/InputError.vue";
import OperationTimeline from "@/components/operations/OperationTimeline.vue";
import StatusIndicator from "@/components/StatusIndicator.vue";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import AppLayout from "@/layouts/AppLayout.vue";
import { Head, Link, router, useForm } from "@inertiajs/vue3";
import {
    BoxIcon,
    ChevronDownIcon,
    DatabaseIcon,
    GitBranchIcon,
    GlobeIcon,
    LayersIcon,
    ListChecksIcon,
    PencilIcon,
    PlusIcon,
    RocketIcon,
    ServerIcon,
    SettingsIcon,
    ShieldCheckIcon,
    ZapIcon,
} from "lucide-vue-next";
import { computed } from "vue";

const props = defineProps<{
    application: Record<string, any>;
    environment: Record<string, any>;
    deploymentRequirements: {
        registryRequired: boolean;
        registryCount: number;
        serverCount: number;
    };
    gatewayRoutePreviews: {
        attachment_id: number;
        caddyfile: string;
    }[];
}>();

const gatewayAttachments = computed(() =>
    props.environment.attachments.filter((attachment) => attachment.role === "gateway"),
);

const resourceAttachments = computed(() =>
    props.environment.attachments.filter((attachment) => attachment.role !== "gateway"),
);

const attachmentIcons: Record<string, object | Function> = {
    database: DatabaseIcon,
    cache: ZapIcon,
    queue: ListChecksIcon,
    storage: BoxIcon,
    gateway: GlobeIcon,
    custom: ServerIcon,
};

const attachmentIcon = (role: string): object | Function => attachmentIcons[role] ?? ServerIcon;

const caddyfilePreviewFor = (attachmentId: number): string =>
    props.gatewayRoutePreviews.find((preview) => preview.attachment_id === attachmentId)
        ?.caddyfile ?? "# No route preview available";

const deployForm = useForm({
    target_commit: "",
});

const deployEnvironment = (): void => {
    deployForm.post(
        route("environment-deployments.store", {
            organisation: route().params.organisation,
            application: props.application.id,
            environment: props.environment.id,
        }),
        {
            preserveScroll: true,
        },
    );
};
</script>

<template>
    <Head :title="`${environment.name} Environment`" />

    <AppLayout
        :breadcrumbs="[
            {
                title: 'Applications',
                href: route('applications.index', { organisation: $page.props.organisation.id }),
            },
            {
                title: application.name,
                href: route('applications.show', {
                    organisation: $page.props.organisation.id,
                    application: application.id,
                }),
            },
            { title: environment.name },
        ]"
    >
        <div class="mx-auto w-full max-w-7xl space-y-6 p-4">
            <!-- Header -->
            <div class="flex flex-wrap items-start justify-between gap-3">
                <div>
                    <div class="flex items-center gap-3">
                        <h2 class="text-2xl font-bold tracking-tight">{{ environment.name }}</h2>
                        <StatusIndicator :status="environment.status" size="md" />
                    </div>
                    <div
                        class="mt-1 flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-muted-foreground"
                    >
                        <span class="flex items-center gap-1.5">
                            <GitBranchIcon class="size-4" />{{ environment.branch }}
                        </span>
                        <span>
                            Scheduler:
                            {{
                                environment.scheduler_enabled
                                    ? `${environment.scheduler_mode} on ${
                                          environment.services?.find(
                                              (service) =>
                                                  service.id ===
                                                  environment.scheduler_target_service_id,
                                          )?.name ?? "selected service"
                                      }`
                                    : "disabled"
                            }}
                        </span>
                    </div>
                </div>
                <div class="flex flex-wrap gap-2">
                    <Button
                        variant="secondary"
                        :as="Link"
                        :href="
                            route('environments.edit', {
                                organisation: $page.props.organisation.id,
                                application: application.id,
                                environment: environment.id,
                            })
                        "
                    >
                        <PencilIcon class="size-4" />
                        Settings
                    </Button>
                    <Button
                        variant="secondary"
                        @click="
                            router.post(
                                route('environment-migrations.store', {
                                    organisation: $page.props.organisation.id,
                                    application: application.id,
                                    environment: environment.id,
                                }),
                            )
                        "
                    >
                        <ListChecksIcon class="size-4" />
                        Migrate
                    </Button>
                    <Button
                        variant="secondary"
                        :as="Link"
                        :href="
                            route('environment-attachments.create', {
                                organisation: $page.props.organisation.id,
                                application: application.id,
                                environment: environment.id,
                            })
                        "
                    >
                        <PlusIcon class="size-4" />
                        Attach
                    </Button>
                    <Button
                        :disabled="deploymentRequirements.registryRequired || deployForm.processing"
                        :title="
                            deploymentRequirements.registryRequired
                                ? 'Configure a registry before deploying to multiple servers.'
                                : undefined
                        "
                        @click="deployEnvironment"
                    >
                        <RocketIcon class="size-4" />
                        Deploy
                    </Button>
                </div>
            </div>

            <Card
                v-if="deploymentRequirements.registryRequired"
                class="border-amber-300 bg-amber-50 dark:bg-amber-950/30"
            >
                <CardHeader>
                    <CardTitle>Registry required</CardTitle>
                    <CardDescription>
                        This environment spans {{ deploymentRequirements.serverCount }} servers.
                        Configure a registry before deploying so every server can pull the same
                        artifact.
                    </CardDescription>
                </CardHeader>
                <CardContent>
                    <Button
                        :as="Link"
                        variant="secondary"
                        :href="
                            route('registries.create', {
                                organisation: $page.props.organisation.id,
                            })
                        "
                    >
                        Add registry
                    </Button>
                </CardContent>
            </Card>

            <!-- Topology -->
            <div class="grid gap-4 lg:grid-cols-3">
                <!-- Network -->
                <div class="space-y-3">
                    <h3 class="px-1 text-sm font-medium text-muted-foreground">Network</h3>

                    <TopologyCard
                        v-for="attachment in gatewayAttachments"
                        :key="attachment.id"
                        :icon="GlobeIcon"
                        title="Gateway"
                        :subtitle="attachment.service_slice?.config?.domain ?? 'Unassigned domain'"
                        :status="attachment.service_slice?.config?.certificate_status ?? 'pending'"
                    >
                        <SpecRow
                            :icon="GlobeIcon"
                            label="Domain"
                            :value="attachment.service_slice?.config?.domain ?? 'not set'"
                        />
                        <SpecRow
                            :icon="ServerIcon"
                            label="Path"
                            :value="attachment.service_slice?.config?.path_prefix ?? '/'"
                        />
                        <SpecRow :icon="ShieldCheckIcon" label="TLS">
                            <StatusIndicator
                                :status="
                                    attachment.service_slice?.config?.tls_enabled === false
                                        ? 'disabled'
                                        : 'enabled'
                                "
                            />
                        </SpecRow>
                        <Collapsible>
                            <CollapsibleTrigger
                                class="flex w-full items-center justify-between pt-1 text-xs text-muted-foreground hover:text-foreground"
                            >
                                View Caddyfile
                                <ChevronDownIcon class="size-3.5" />
                            </CollapsibleTrigger>
                            <CollapsibleContent>
                                <pre class="mt-2 overflow-x-auto rounded-md bg-muted p-3 text-xs">{{
                                    caddyfilePreviewFor(attachment.id)
                                }}</pre>
                            </CollapsibleContent>
                        </Collapsible>
                    </TopologyCard>

                    <Card v-if="gatewayAttachments.length === 0" class="border-dashed">
                        <CardContent class="space-y-3 p-5 text-center">
                            <p class="text-sm text-muted-foreground">
                                No gateway routes configured.
                            </p>
                            <Button
                                :as="Link"
                                size="sm"
                                variant="secondary"
                                :href="
                                    route('gateway.routes.index', {
                                        organisation: $page.props.organisation.id,
                                        application: application.id,
                                        environment: environment.id,
                                    })
                                "
                            >
                                Manage routes
                            </Button>
                        </CardContent>
                    </Card>
                </div>

                <!-- Compute -->
                <div class="space-y-3">
                    <h3 class="px-1 text-sm font-medium text-muted-foreground">Compute</h3>

                    <TopologyCard
                        v-for="service in environment.services"
                        :key="service.id"
                        :icon="ServerIcon"
                        :title="service.name"
                        :subtitle="service.type"
                        :status="service.status"
                    >
                        <SpecRow
                            :icon="LayersIcon"
                            label="Replicas"
                            :value="service.replicas?.length ?? 0"
                        />
                        <SpecRow
                            :icon="LayersIcon"
                            label="Slices"
                            :value="service.slices?.length ?? 0"
                        />
                        <SpecRow
                            :icon="ServerIcon"
                            label="Deploy policy"
                            :value="service.deploy_policy ?? 'default'"
                        />
                        <Button
                            :as="Link"
                            size="sm"
                            variant="secondary"
                            class="mt-1 w-full"
                            :href="
                                route('environment-services.show', {
                                    organisation: $page.props.organisation.id,
                                    application: environment.application_id,
                                    environment: environment.id,
                                    service: service.id,
                                })
                            "
                        >
                            <SettingsIcon class="size-4" />
                            Open service
                        </Button>
                    </TopologyCard>

                    <Card v-if="(environment.services?.length ?? 0) === 0" class="border-dashed">
                        <CardContent class="p-5 text-center text-sm text-muted-foreground">
                            No services in this environment.
                        </CardContent>
                    </Card>
                </div>

                <!-- Resources -->
                <div class="space-y-3">
                    <h3 class="px-1 text-sm font-medium text-muted-foreground">Resources</h3>

                    <TopologyCard
                        v-for="attachment in resourceAttachments"
                        :key="attachment.id"
                        :icon="attachmentIcon(attachment.role)"
                        :title="attachment.role.replaceAll('_', ' ')"
                        :subtitle="attachment.service?.name"
                    >
                        <SpecRow
                            :icon="ServerIcon"
                            label="Service"
                            :value="attachment.service?.name ?? '—'"
                        />
                        <SpecRow
                            :icon="LayersIcon"
                            label="Slice"
                            :value="attachment.service_slice?.name ?? 'service level'"
                        />
                        <Button
                            :as="Link"
                            size="sm"
                            variant="secondary"
                            class="mt-1 w-full"
                            :href="
                                route('environment-attachments.edit', {
                                    organisation: $page.props.organisation.id,
                                    application: application.id,
                                    environment: environment.id,
                                    attachment: attachment.id,
                                })
                            "
                        >
                            <SettingsIcon class="size-4" />
                            Edit attachment
                        </Button>
                    </TopologyCard>

                    <Card v-if="resourceAttachments.length === 0" class="border-dashed">
                        <CardContent class="space-y-3 p-5 text-center">
                            <p class="text-sm text-muted-foreground">No resources attached.</p>
                            <Button
                                :as="Link"
                                size="sm"
                                variant="secondary"
                                :href="
                                    route('environment-attachments.create', {
                                        organisation: $page.props.organisation.id,
                                        application: application.id,
                                        environment: environment.id,
                                    })
                                "
                            >
                                <PlusIcon class="size-4" />
                                Attach resource
                            </Button>
                        </CardContent>
                    </Card>

                    <!-- Variables -->
                    <Card>
                        <CardHeader class="pb-3">
                            <div class="flex items-center justify-between">
                                <CardTitle class="text-base">Variables</CardTitle>
                                <Button
                                    :as="Link"
                                    size="xs"
                                    variant="secondary"
                                    :href="
                                        route('environment-variables.index', {
                                            organisation: $page.props.organisation.id,
                                            application: application.id,
                                            environment: environment.id,
                                        })
                                    "
                                >
                                    Manage
                                </Button>
                            </div>
                        </CardHeader>
                        <CardContent class="flex flex-wrap gap-2">
                            <Badge
                                v-for="variable in environment.variables"
                                :key="variable.id"
                                :variant="variable.source === 'user' ? 'secondary' : 'outline'"
                            >
                                {{ variable.key }}
                                <span v-if="!variable.overridable"> · locked</span>
                            </Badge>
                            <span
                                v-if="(environment.variables?.length ?? 0) === 0"
                                class="text-sm text-muted-foreground"
                            >
                                No variables set.
                            </span>
                        </CardContent>
                    </Card>
                </div>
            </div>

            <!-- Deploy a specific commit -->
            <Collapsible>
                <Card>
                    <CollapsibleTrigger class="w-full">
                        <CardHeader class="flex-row items-center justify-between">
                            <div class="text-left">
                                <CardTitle class="text-base">Deploy a specific commit</CardTitle>
                                <CardDescription>
                                    Pin this deployment to a commit SHA instead of the branch head.
                                </CardDescription>
                            </div>
                            <ChevronDownIcon class="size-4 text-muted-foreground" />
                        </CardHeader>
                    </CollapsibleTrigger>
                    <CollapsibleContent>
                        <CardContent>
                            <form
                                class="flex flex-col gap-3 md:flex-row md:items-end"
                                @submit.prevent="deployEnvironment"
                            >
                                <div class="grid flex-1 gap-2">
                                    <Label for="target_commit">Commit SHA</Label>
                                    <Input
                                        id="target_commit"
                                        v-model="deployForm.target_commit"
                                        placeholder="Leave blank to resolve the branch head"
                                        maxlength="40"
                                    />
                                    <InputError :message="deployForm.errors.target_commit" />
                                </div>
                                <Button
                                    type="submit"
                                    :disabled="
                                        deploymentRequirements.registryRequired ||
                                        deployForm.processing
                                    "
                                >
                                    <RocketIcon class="size-4" />
                                    Deploy commit
                                </Button>
                            </form>
                        </CardContent>
                    </CollapsibleContent>
                </Card>
            </Collapsible>

            <!-- Activity -->
            <div class="grid gap-4 lg:grid-cols-[2fr_1fr]">
                <Card>
                    <CardHeader>
                        <CardTitle class="text-base">Operations</CardTitle>
                    </CardHeader>
                    <CardContent>
                        <OperationTimeline :operations="environment.operations" />
                    </CardContent>
                </Card>

                <Card>
                    <CardHeader>
                        <div class="flex items-center justify-between">
                            <CardTitle class="text-base">Builds</CardTitle>
                            <Button
                                :as="Link"
                                size="xs"
                                variant="secondary"
                                :href="
                                    route('build-artifacts.index', {
                                        organisation: $page.props.organisation.id,
                                        application: application.id,
                                        environment: environment.id,
                                    })
                                "
                            >
                                View all
                            </Button>
                        </div>
                    </CardHeader>
                    <CardContent class="grid gap-2">
                        <div
                            v-for="artifact in environment.build_artifacts"
                            :key="artifact.id"
                            class="rounded-md border p-3 text-sm"
                        >
                            <div class="flex flex-wrap items-center gap-2">
                                <StatusIndicator :status="artifact.status" />
                                <span class="font-mono text-xs">{{ artifact.commit_sha }}</span>
                            </div>
                            <p class="mt-1 truncate text-xs text-muted-foreground">
                                {{ artifact.registry_ref ?? "No registry ref" }}
                            </p>
                        </div>
                        <div
                            v-if="(environment.build_artifacts?.length ?? 0) === 0"
                            class="rounded-md border border-dashed p-4 text-sm text-muted-foreground"
                        >
                            No builds recorded.
                        </div>
                    </CardContent>
                </Card>
            </div>
        </div>
    </AppLayout>
</template>
