import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import { ArrowLeft, Link2, Plus, Trash2 } from "lucide-react";
import { useDeferredValue, useMemo, useState } from "react";
import { useAuth } from "react-oidc-context";
import { Link, useParams } from "react-router-dom";
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";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "../../components/ui/table";
import { toast } from "../../components/ui/use-toast";
import {
  type DevAssignableUser,
  addClientRelation,
  fetchClient,
  fetchClientRelations,
  fetchDevUsers,
  removeClientRelation,
} from "../../lib/devApi";
import { t } from "../../lib/i18n";
import { resolveProfileRole } from "../../lib/role";
import { ClientDetailTabs } from "./ClientDetailTabs";

const relationOptions = [
  "admins",
  "config_editor",
  "secret_viewer",
  "secret_rotator",
  "jwks_viewer",
  "jwks_operator",
  "consent_viewer",
  "consent_revoker",
  "relationship_viewer",
  "audit_viewer",
] as const;

type RelationOption = (typeof relationOptions)[number];

function relationLabel(relation: RelationOption) {
  return t(`ui.dev.clients.relationships.option.${relation}.label`, relation);
}

function relationDescription(relation: RelationOption) {
  return t(
    `ui.dev.clients.relationships.option.${relation}.description`,
    relation,
  );
}

function formatUserLabel(user: DevAssignableUser) {
  const primary = user.name.trim() || user.email.trim();
  return `${primary} (${user.email.trim()})`;
}

function ClientRelationsPage() {
  const params = useParams();
  const auth = useAuth();
  const queryClient = useQueryClient();
  const clientId = params.id ?? "";
  const [selectedRelations, setSelectedRelations] = useState<RelationOption[]>(
    [],
  );
  const [userSearch, setUserSearch] = useState("");
  const deferredUserSearch = useDeferredValue(userSearch.trim());
  const [selectedUser, setSelectedUser] = useState<DevAssignableUser | null>(
    null,
  );
  const [isSearchOpen, setIsSearchOpen] = useState(false);

  const systemRole = resolveProfileRole(
    auth.user?.profile as Record<string, unknown> | undefined,
  );

  const { data: clientData } = useQuery({
    queryKey: ["client", clientId],
    queryFn: () => fetchClient(clientId),
    enabled: clientId.length > 0,
  });

  const {
    data: relationData,
    isLoading,
    error,
  } = useQuery({
    queryKey: ["client-relations", clientId],
    queryFn: () => fetchClientRelations(clientId),
    enabled: clientId.length > 0,
  });

  // Calculate permissions for UI hints and button states
  const isSuperAdmin = systemRole === "super_admin";
  const myUserId = auth.user?.profile.sub;
  const isRpAdmin = useMemo(() => {
    if (isSuperAdmin) return true;
    if (!relationData?.items || !myUserId) return false;
    return relationData.items.some(
      (item) =>
        item.subject === `User:${myUserId}` && item.relation === "admins",
    );
  }, [relationData?.items, myUserId, isSuperAdmin]);

  const canManageRelations = isRpAdmin || isSuperAdmin;

  const isRelationshipViewForbidden =
    (error as AxiosError | null)?.response?.status === 403;
  const relationshipViewForbiddenMessage = t(
    "msg.dev.clients.relationships.view_forbidden",
    "이 RP의 관계를 조회할 권한이 없습니다. 관리자에게 관계 조회 또는 RP 관리자 관계 부여를 요청해 주세요.",
  );

  const {
    data: userSearchData,
    isFetching: isUserSearchLoading,
    error: userSearchError,
  } = useQuery({
    queryKey: ["dev-users", deferredUserSearch],
    queryFn: () => fetchDevUsers(deferredUserSearch, 10, clientId),
    enabled:
      clientId.length > 0 &&
      deferredUserSearch.length > 0 &&
      selectedUser == null &&
      !isRelationshipViewForbidden,
  });

  const sortedItems = useMemo(() => {
    return [...(relationData?.items ?? [])].sort((a, b) => {
      const relationCompare = a.relation.localeCompare(b.relation);
      if (relationCompare !== 0) {
        return relationCompare;
      }
      return a.subject.localeCompare(b.subject);
    });
  }, [relationData?.items]);

  const selectedUserExistingRelations = useMemo(() => {
    if (!selectedUser) {
      return new Set<string>();
    }

    return new Set(
      sortedItems
        .filter((item) => item.subjectId === selectedUser.id)
        .map((item) => item.relation),
    );
  }, [selectedUser, sortedItems]);

  const addMutation = useMutation({
    mutationFn: async () => {
      if (!selectedUser) {
        throw new Error(
          t(
            "msg.dev.clients.relationships.user_required",
            "추가할 사용자를 선택하세요.",
          ),
        );
      }

      const pendingRelations = selectedRelations.filter(
        (relation) => !selectedUserExistingRelations.has(relation),
      );
      for (const relation of pendingRelations) {
        await addClientRelation(clientId, {
          relation,
          userId: selectedUser.id,
        });
      }
    },
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: ["client-relations", clientId],
      });
      setSelectedRelations([]);
      setSelectedUser(null);
      setUserSearch("");
      setIsSearchOpen(false);
      toast(
        t(
          "msg.dev.clients.relationships.added",
          "Relationship가 추가되었습니다.",
        ),
      );
    },
    onError: (err) => {
      toast(
        t(
          "msg.dev.clients.relationships.add_error",
          "Relationship 추가 실패: {{error}}",
          {
            error:
              (err as AxiosError<{ error?: string }>).response?.data?.error ??
              (err as Error).message,
          },
        ),
        "error",
      );
    },
  });

  const removeMutation = useMutation({
    mutationFn: (payload: { relation: string; subject: string }) =>
      removeClientRelation(clientId, payload.relation, payload.subject),
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: ["client-relations", clientId],
      });
      toast(
        t(
          "msg.dev.clients.relationships.removed",
          "Relationship가 제거되었습니다.",
        ),
      );
    },
    onError: (err) => {
      toast(
        t(
          "msg.dev.clients.relationships.remove_error",
          "Relationship 제거 실패: {{error}}",
          {
            error:
              (err as AxiosError<{ error?: string }>).response?.data?.error ??
              (err as Error).message,
          },
        ),
        "error",
      );
    },
  });

  const handleAdd = () => {
    if (!canManageRelations) {
      toast(
        t(
          "msg.dev.clients.relationships.add_forbidden_viewer",
          "'관계 조회' 권한만으로는 새로운 관계를 추가하거나 사용자를 검색할 수 없습니다. 'RP 관리자' 권한이 필요합니다.",
        ),
        "error",
      );
      return;
    }
    if (!selectedUser) {
      toast(
        t(
          "msg.dev.clients.relationships.user_required",
          "추가할 사용자를 선택하세요.",
        ),
        "error",
      );
      return;
    }

    const pendingRelations = selectedRelations.filter(
      (relation) => !selectedUserExistingRelations.has(relation),
    );
    if (pendingRelations.length === 0) {
      toast(
        t(
          "msg.dev.clients.relationships.relation_required",
          "추가할 관계를 하나 이상 선택하세요.",
        ),
        "error",
      );
      return;
    }

    addMutation.mutate();
  };

  const handleRelationToggle = (relation: RelationOption) => {
    setSelectedRelations((current) =>
      current.includes(relation)
        ? current.filter((item) => item !== relation)
        : [...current, relation],
    );
  };

  const handleSelectUser = (user: DevAssignableUser) => {
    setSelectedUser(user);
    setUserSearch(formatUserLabel(user));
    setIsSearchOpen(false);
  };

  const handleRemove = (targetRelation: string, subject: string) => {
    if (
      window.confirm(
        t(
          "msg.dev.clients.relationships.remove_confirm",
          "이 relationship를 제거하시겠습니까?",
        ),
      )
    ) {
      removeMutation.mutate({ relation: targetRelation, subject });
    }
  };

  if (!clientId) {
    return (
      <div className="p-8 text-center">
        {t("msg.dev.clients.details.missing_id", "Client ID가 필요합니다.")}
      </div>
    );
  }

  const isUserSearchForbidden =
    (userSearchError as AxiosError | null)?.response?.status === 403;

  return (
    <div className="space-y-8">
      <header className="space-y-4">
        <div className="flex flex-wrap justify-between gap-4">
          <div className="space-y-2">
            <nav className="flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
              <Link to="/" className="hover:text-primary">
                {t("ui.dev.clients.consents.breadcrumb.home", "Home")}
              </Link>
              <span>/</span>
              <Link to="/clients" className="hover:text-primary">
                {t("ui.dev.clients.consents.breadcrumb.clients", "Apps")}
              </Link>
              <span>/</span>
              <span>{clientData?.client?.name || clientId}</span>
              <span>/</span>
              <span className="text-foreground font-semibold">
                {t("ui.dev.clients.details.tab.relationships", "Relationships")}
              </span>
            </nav>
            <div className="flex items-center gap-2">
              <Button variant="ghost" size="icon" asChild>
                <Link to={`/clients/${clientId}`}>
                  <ArrowLeft className="h-4 w-4" />
                </Link>
              </Button>
              <div>
                <p className="text-3xl font-black leading-tight">
                  {t(
                    "ui.dev.clients.relationships.title",
                    "Client Relationships",
                  )}
                </p>
                <p className="text-muted-foreground">
                  {t(
                    "msg.dev.clients.relationships.subtitle",
                    "RP direct operator relation을 조회하고 User 단위로 추가·삭제합니다.",
                  )}
                </p>
              </div>
            </div>
          </div>
          <div className="flex items-center gap-3">
            <Badge
              variant={
                clientData?.client?.status === "active" ? "info" : "muted"
              }
            >
              {clientData?.client?.status === "active"
                ? t("ui.common.status.active", "Active")
                : t("ui.common.status.inactive", "Inactive")}
            </Badge>
          </div>
        </div>
        <ClientDetailTabs activeTab="relationships" clientId={clientId} />
      </header>

      <Card className="glass-panel">
        <CardHeader>
          <CardTitle>
            {t("ui.dev.clients.relationships.add_title", "Add Relationship")}
          </CardTitle>
          <CardDescription>
            {t(
              "msg.dev.clients.relationships.add_description",
              "사용자를 검색해 선택하고, 하나 이상의 운영 관계를 한 번에 부여할 수 있습니다.",
            )}
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-6">
          {isRelationshipViewForbidden ? (
            <div className="rounded-md border border-border bg-muted/30 p-4 text-sm text-muted-foreground">
              {relationshipViewForbiddenMessage}
            </div>
          ) : (
            <>
              <div className="space-y-2">
                <Label htmlFor="user-search-input">
                  {t("ui.dev.clients.relationships.user_search", "사용자")}
                </Label>
                <div className="relative">
                  <Input
                    id="user-search-input"
                    value={userSearch}
                    onFocus={() => {
                      if (!selectedUser && userSearch.trim() !== "") {
                        setIsSearchOpen(true);
                      }
                    }}
                    onChange={(event) => {
                      setSelectedUser(null);
                      setUserSearch(event.target.value);
                      setIsSearchOpen(true);
                    }}
                    placeholder={t(
                      "ui.dev.clients.relationships.user_search_placeholder",
                      "이름 또는 이메일 검색...",
                    )}
                  />
                  {isSearchOpen &&
                    selectedUser == null &&
                    userSearch.trim() !== "" && (
                      <div className="absolute z-20 mt-2 max-h-64 w-full overflow-y-auto rounded-md border border-border bg-background shadow-lg">
                        {isUserSearchLoading ? (
                          <div className="px-3 py-2 text-sm text-muted-foreground">
                            {t(
                              "msg.dev.clients.relationships.search_loading",
                              "사용자를 찾는 중입니다...",
                            )}
                          </div>
                        ) : isUserSearchForbidden ? (
                          <div className="px-4 py-8 text-center text-sm text-destructive font-medium border-b border-border/40 bg-destructive/5 flex flex-col gap-2">
                            <p>
                              {t(
                                "msg.dev.clients.relationships.search_forbidden_user",
                                "일반 사용자는 관계 추가를 위한 사용자 검색을 사용할 수 없습니다.",
                              )}
                            </p>
                            <p className="text-xs text-muted-foreground/80 font-normal">
                              {t(
                                "msg.dev.clients.relationships.search_forbidden_user_hint",
                                "'관계 조회' 권한만으로는 사용자 검색이 제한됩니다. 'RP 관리자' 관계가 필요합니다.",
                              )}
                            </p>
                          </div>
                        ) : (userSearchData?.items ?? []).length > 0 ? (
                          (userSearchData?.items ?? []).map((user) => (
                            <button
                              key={user.id}
                              type="button"
                              className="flex w-full flex-col gap-1 px-3 py-2 text-left hover:bg-muted/40 border-b border-border/40 last:border-b-0"
                              onMouseDown={(event) => {
                                event.preventDefault();
                                handleSelectUser(user);
                              }}
                            >
                              <span className="text-sm font-semibold">
                                {user.name || user.email}
                              </span>
                              <span className="text-xs text-muted-foreground">
                                {user.email}
                                {user.loginId ? ` · ${user.loginId}` : ""}
                              </span>
                            </button>
                          ))
                        ) : (
                          <div className="px-3 py-4 text-center text-sm text-muted-foreground">
                            {t(
                              "msg.dev.clients.relationships.search_empty",
                              "검색 결과가 없습니다.",
                            )}
                          </div>
                        )}
                      </div>
                    )}
                </div>
                {selectedUser && (
                  <p className="text-xs text-muted-foreground">
                    {t(
                      "msg.dev.clients.relationships.selected_user",
                      "선택된 사용자: {{user}}",
                      { user: formatUserLabel(selectedUser) },
                    )}
                  </p>
                )}
              </div>

              <div className="space-y-3">
                <Label>
                  {t("ui.dev.clients.relationships.relation", "Relation")}
                </Label>
                <div className="grid gap-3 md:grid-cols-2">
                  {relationOptions.map((relation) => {
                    const disabled =
                      selectedUserExistingRelations.has(relation);
                    const isSelected = selectedRelations.includes(relation);
                    return (
                      <label
                        key={relation}
                        className={`flex gap-3 rounded-xl border p-4 transition-all ${
                          disabled
                            ? "border-border/60 bg-muted/30 opacity-60"
                            : isSelected
                              ? "border-primary bg-primary/10 shadow-[0_0_0_1px_rgba(59,130,246,0.35)] ring-1 ring-primary/30"
                              : "border-border bg-background hover:border-primary/40 hover:bg-muted/20"
                        }`}
                      >
                        <input
                          type="checkbox"
                          className="mt-1 h-4 w-4 accent-primary"
                          checked={isSelected || disabled}
                          disabled={disabled}
                          onChange={() => handleRelationToggle(relation)}
                        />
                        <div className="space-y-1">
                          <div
                            className={`text-sm font-semibold ${
                              isSelected && !disabled ? "text-primary" : ""
                            }`}
                          >
                            {relationLabel(relation)}
                          </div>
                          <div className="text-xs text-muted-foreground">
                            {relationDescription(relation)}
                          </div>
                          <div
                            className={`text-[11px] uppercase tracking-wide ${
                              isSelected && !disabled
                                ? "text-primary/80"
                                : "text-muted-foreground/80"
                            }`}
                          >
                            {relation}
                          </div>
                        </div>
                      </label>
                    );
                  })}
                </div>
              </div>

              <div className="flex justify-end">
                <Button
                  onClick={handleAdd}
                  disabled={addMutation.isPending || !canManageRelations}
                  className="gap-2"
                >
                  <Plus className="h-4 w-4" />
                  {addMutation.isPending
                    ? t("msg.common.loading", "Loading...")
                    : t("ui.dev.clients.relationships.add", "Add")}
                </Button>
              </div>
            </>
          )}
        </CardContent>
      </Card>

      <Card className="glass-panel">
        <CardHeader>
          <CardTitle className="flex items-center gap-2">
            <Link2 className="h-5 w-5" />
            {t(
              "ui.dev.clients.relationships.list_title",
              "Assigned Relationships",
            )}
          </CardTitle>
          <CardDescription>
            {t(
              "msg.dev.clients.relationships.list_description",
              "현재 RP에 직접 부여된 operator relation 목록입니다.",
            )}
          </CardDescription>
        </CardHeader>
        <CardContent>
          {isRelationshipViewForbidden ? (
            <div className="rounded-md border border-border bg-muted/30 p-4 text-sm text-muted-foreground">
              {relationshipViewForbiddenMessage}
            </div>
          ) : error ? (
            <div className="rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive">
              {t(
                "msg.dev.clients.relationships.load_error",
                "Relationship 조회 실패: {{error}}",
                {
                  error:
                    (error as AxiosError<{ error?: string }>).response?.data
                      ?.error ?? (error as Error).message,
                },
              )}
            </div>
          ) : isLoading ? (
            <div className="py-8 text-center text-sm text-muted-foreground">
              {t(
                "msg.dev.clients.relationships.loading",
                "Relationship를 불러오는 중입니다...",
              )}
            </div>
          ) : sortedItems.length === 0 ? (
            <div className="py-8 text-center text-sm text-muted-foreground">
              {t(
                "msg.dev.clients.relationships.empty",
                "직접 부여된 relationship가 없습니다.",
              )}
            </div>
          ) : (
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>
                    {t("ui.dev.clients.relationships.relation", "Relation")}
                  </TableHead>
                  <TableHead>
                    {t("ui.dev.clients.relationships.subject", "Subject")}
                  </TableHead>
                  <TableHead>
                    {t("ui.dev.clients.relationships.subject_type", "Type")}
                  </TableHead>
                  <TableHead className="w-[120px] text-right">
                    {t("ui.dev.clients.table.actions", "액션")}
                  </TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {sortedItems.map((item) => (
                  <TableRow key={`${item.relation}:${item.subject}`}>
                    <TableCell>
                      <div className="space-y-1">
                        <div className="font-medium">
                          {relationLabel(item.relation as RelationOption)}
                        </div>
                        <div className="text-xs text-muted-foreground">
                          {relationDescription(item.relation as RelationOption)}
                        </div>
                      </div>
                    </TableCell>
                    <TableCell>
                      <div className="space-y-1">
                        <div className="font-medium">
                          {item.userName || item.userEmail || item.subject}
                        </div>
                        {(item.userEmail || item.userLoginId) && (
                          <div className="text-xs text-muted-foreground">
                            {[item.userEmail, item.userLoginId]
                              .filter(Boolean)
                              .join(" · ")}
                          </div>
                        )}
                        <div className="font-mono text-xs text-muted-foreground">
                          {item.subject}
                        </div>
                        {item.subjectId && (
                          <div className="text-xs text-muted-foreground">
                            ID: {item.subjectId}
                          </div>
                        )}
                      </div>
                    </TableCell>
                    <TableCell>
                      <Badge variant="outline">{item.subjectType || "-"}</Badge>
                    </TableCell>
                    <TableCell className="text-right">
                      <Button
                        variant="ghost"
                        size="sm"
                        className="gap-2 text-destructive hover:text-destructive"
                        disabled={
                          removeMutation.isPending || !canManageRelations
                        }
                        onClick={() =>
                          handleRemove(item.relation, item.subject)
                        }
                      >
                        <Trash2 className="h-4 w-4" />
                        {t("ui.common.delete", "Delete")}
                      </Button>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          )}
        </CardContent>
      </Card>
    </div>
  );
}

export default ClientRelationsPage;
