"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { Edit, Eye, Plus, Trash2, Upload } from "lucide-react";

import ConfirmDialog from "@/components/common/ConfirmDialog";
import DataTable, { type DataTableColumn } from "@/components/common/DataTable";
import SearchInput from "@/components/common/SearchInput";
import { useToast } from "@/components/common/ToastProvider";
import { Button, buttonVariants } from "@/components/ui/button";
import CustomerFormDialog from "@/components/customers/CustomerFormDialog";
import CustomerImportDialog from "@/components/customers/CustomerImportDialog";
import CustomerStatusBadge from "@/components/customers/CustomerStatusBadge";
import { api } from "@/lib/api";
import { hasPermission } from "@/lib/permissions";
import type { CurrentUser } from "@/types/rbac";
import type { Customer, CustomerImportCommitResponse, CustomerPayload, CustomerStatus, CustomerType } from "@/types/customer";

const pageSize = 10;

function getErrorMessage(error: unknown) {
  if (typeof error === "object" && error !== null && "response" in error) {
    const response = (error as { response?: { data?: { detail?: string } } }).response;
    return response?.data?.detail ?? "Aktion konnte nicht abgeschlossen werden";
  }
  return "Aktion konnte nicht abgeschlossen werden";
}

function formatDate(value: string) {
  return new Intl.DateTimeFormat("de-DE", {
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
  }).format(new Date(value));
}

function getPrimaryCity(customer: Customer) {
  return customer.addresses.find((address) => address.is_primary)?.city
    || customer.addresses[0]?.city
    || "-";
}

function getSortableValue(customer: Customer, key: string) {
  if (key === "city") {
    return getPrimaryCity(customer).toLowerCase();
  }
  const value = customer[key as keyof Customer];
  return typeof value === "string" ? value.toLowerCase() : value;
}

export default function CustomersPage() {
  const { showToast } = useToast();
  const [customers, setCustomers] = useState<Customer[]>([]);
  const [currentUser, setCurrentUser] = useState<CurrentUser | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [formError, setFormError] = useState("");
  const [deleteError, setDeleteError] = useState("");
  const [pending, setPending] = useState(false);
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState<CustomerStatus | "all">("all");
  const [typeFilter, setTypeFilter] = useState<CustomerType | "all">("all");
  const [sortKey, setSortKey] = useState("created_at");
  const [sortDirection, setSortDirection] = useState<"asc" | "desc">("desc");
  const [page, setPage] = useState(1);
  const [formOpen, setFormOpen] = useState(false);
  const [importOpen, setImportOpen] = useState(false);
  const [selectedCustomer, setSelectedCustomer] = useState<Customer | null>(null);
  const [deleteCustomer, setDeleteCustomer] = useState<Customer | null>(null);

  const loadCustomers = useCallback(async () => {
    try {
      const [customersResponse, meResponse] = await Promise.all([
        api.get<Customer[]>("/customers"),
        api.get<CurrentUser>("/me"),
      ]);
      setCustomers(customersResponse.data);
      setCurrentUser(meResponse.data);
    } catch (err) {
      setError(getErrorMessage(err));
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    queueMicrotask(() => {
      void loadCustomers();
    });
  }, [loadCustomers]);

  const filteredCustomers = useMemo(() => {
    const term = search.trim().toLowerCase();

    return customers
      .filter((customer) => {
        if (!term) {
          return true;
        }
        return [
          customer.customer_number,
          customer.company_name,
          customer.legal_name,
          customer.industry,
          customer.email,
          customer.phone,
          getPrimaryCity(customer),
        ].some((value) => value.toLowerCase().includes(term));
      })
      .filter((customer) => statusFilter === "all" || customer.status === statusFilter)
      .filter((customer) => typeFilter === "all" || customer.customer_type === typeFilter)
      .sort((first, second) => {
        const firstValue = getSortableValue(first, sortKey);
        const secondValue = getSortableValue(second, sortKey);
        if (firstValue === secondValue) {
          return 0;
        }
        const result = firstValue > secondValue ? 1 : -1;
        return sortDirection === "asc" ? result : -result;
      });
  }, [customers, search, sortDirection, sortKey, statusFilter, typeFilter]);

  const pageCount = Math.max(1, Math.ceil(filteredCustomers.length / pageSize));
  const currentPage = Math.min(page, pageCount);
  const pageCustomers = filteredCustomers.slice((currentPage - 1) * pageSize, currentPage * pageSize);
  const canImportCustomers = hasPermission(currentUser, "customers.create") || hasPermission(currentUser, "customers.update");

  const columns: DataTableColumn<Customer>[] = [
    { key: "customer_number", label: "Kundennummer", sortable: true, render: (customer) => customer.customer_number },
    { key: "company_name", label: "Firmenname", sortable: true, render: (customer) => <span className="font-medium text-slate-950">{customer.company_name}</span> },
    { key: "customer_type", label: "Typ", sortable: true, render: (customer) => customer.customer_type },
    { key: "status", label: "Status", sortable: true, render: (customer) => <CustomerStatusBadge status={customer.status} /> },
    { key: "industry", label: "Branche", sortable: true, render: (customer) => customer.industry || "-" },
    { key: "email", label: "E-Mail", sortable: true, render: (customer) => customer.email || "-" },
    { key: "phone", label: "Telefon", sortable: true, render: (customer) => customer.phone || "-" },
    { key: "city", label: "Ort", sortable: true, render: (customer) => getPrimaryCity(customer) },
    { key: "created_at", label: "Erstellt", sortable: true, render: (customer) => formatDate(customer.created_at) },
    {
      key: "actions",
      label: "Aktionen",
      className: "px-4 py-3 text-right",
      render: (customer) => (
        <div className="flex justify-end gap-2">
          <Link href={`/customers/${customer.id}`} className={buttonVariants({ variant: "ghost", size: "icon-sm" })} title="Details">
            <Eye size={16} />
          </Link>
          {hasPermission(currentUser, "customers.update") && (
            <Button type="button" variant="ghost" size="icon-sm" title="Bearbeiten" onClick={() => openEditDialog(customer)}>
              <Edit size={16} />
            </Button>
          )}
          {hasPermission(currentUser, "customers.delete") && (
            <Button type="button" variant="destructive" size="icon-sm" title="Löschen" onClick={() => setDeleteCustomer(customer)}>
              <Trash2 size={16} />
            </Button>
          )}
        </div>
      ),
    },
  ];

  function handleSort(key: string) {
    if (sortKey === key) {
      setSortDirection((current) => (current === "asc" ? "desc" : "asc"));
      return;
    }
    setSortKey(key);
    setSortDirection("asc");
  }

  function openCreateDialog() {
    setSelectedCustomer(null);
    setFormError("");
    setFormOpen(true);
  }

  function openEditDialog(customer: Customer) {
    setSelectedCustomer(customer);
    setFormError("");
    setFormOpen(true);
  }

  async function saveCustomer(payload: CustomerPayload) {
    setPending(true);
    setFormError("");
    try {
      if (selectedCustomer) {
        const response = await api.put<Customer>(`/customers/${selectedCustomer.id}`, payload);
        setCustomers((current) => current.map((customer) => customer.id === selectedCustomer.id ? response.data : customer));
        showToast({ type: "success", title: "Kunde aktualisiert", description: response.data.company_name });
      } else {
        const response = await api.post<Customer>("/customers", payload);
        setCustomers((current) => [response.data, ...current]);
        showToast({ type: "success", title: "Kunde erstellt", description: response.data.company_name });
      }
      setFormOpen(false);
    } catch (err) {
      const message = getErrorMessage(err);
      setFormError(message);
      showToast({ type: "error", title: "Kunde konnte nicht gespeichert werden", description: message });
    } finally {
      setPending(false);
    }
  }

  async function confirmDelete() {
    if (!deleteCustomer) {
      return;
    }
    setPending(true);
    setDeleteError("");
    try {
      await api.delete(`/customers/${deleteCustomer.id}`);
      setCustomers((current) => current.filter((customer) => customer.id !== deleteCustomer.id));
      showToast({ type: "success", title: "Kunde gelöscht", description: deleteCustomer.company_name });
      setDeleteCustomer(null);
    } catch (err) {
      const message = getErrorMessage(err);
      setDeleteError(message);
      showToast({ type: "error", title: "Kunde konnte nicht gelöscht werden", description: message });
    } finally {
      setPending(false);
    }
  }

  async function handleImportCommitted(result: CustomerImportCommitResponse) {
    showToast({
      type: "success",
      title: "Kundenimport abgeschlossen",
      description: `${result.created} erstellt, ${result.updated} aktualisiert, ${result.skipped} übersprungen`,
    });
    setLoading(true);
    await loadCustomers();
  }

  return (
    <div className="space-y-6">
      <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
        <div>
          <h1 className="text-3xl font-bold text-slate-950">Kunden</h1>
          <p className="mt-1 text-sm text-slate-500">{filteredCustomers.length} von {customers.length} Kunden</p>
        </div>
        <div className="flex flex-wrap gap-2">
          {canImportCustomers && (
            <Button type="button" variant="outline" onClick={() => setImportOpen(true)}>
              <Upload size={16} />
              Import
            </Button>
          )}
          {hasPermission(currentUser, "customers.create") && (
            <Button type="button" onClick={openCreateDialog}>
              <Plus size={16} />
              Neuer Kunde
            </Button>
          )}
        </div>
      </div>

      <div className="flex flex-col gap-3 rounded-lg border bg-white p-4 lg:flex-row lg:items-center">
        <SearchInput value={search} onChange={(value) => { setSearch(value); setPage(1); }} placeholder="Kunden suchen" />
        <select value={statusFilter} onChange={(event) => { setStatusFilter(event.target.value as CustomerStatus | "all"); setPage(1); }} className="h-8 rounded-lg border border-input bg-transparent px-2.5 text-sm">
          <option value="all">Alle Status</option>
          <option value="lead">Lead</option>
          <option value="active">Aktiv</option>
          <option value="inactive">Inaktiv</option>
          <option value="blocked">Gesperrt</option>
          <option value="archived">Archiviert</option>
        </select>
        <select value={typeFilter} onChange={(event) => { setTypeFilter(event.target.value as CustomerType | "all"); setPage(1); }} className="h-8 rounded-lg border border-input bg-transparent px-2.5 text-sm">
          <option value="all">Alle Typen</option>
          <option value="company">Unternehmen</option>
          <option value="private">Privat</option>
          <option value="public_sector">Öffentlicher Sektor</option>
          <option value="partner">Partner</option>
          <option value="supplier">Lieferant</option>
        </select>
      </div>

      <DataTable
        columns={columns}
        rows={pageCustomers}
        rowKey={(customer) => customer.id}
        sortKey={sortKey}
        sortDirection={sortDirection}
        loading={loading}
        error={error}
        emptyTitle="Keine Kunden gefunden"
        emptyDescription="Passe Suche oder Filter an oder erstelle einen neuen Kunden."
        onSort={handleSort}
      />

      <div className="flex items-center justify-between text-sm text-slate-600">
        <span>Seite {currentPage} von {pageCount}</span>
        <div className="flex gap-2">
          <Button type="button" variant="outline" disabled={currentPage === 1} onClick={() => setPage((current) => Math.max(1, current - 1))}>Zurück</Button>
          <Button type="button" variant="outline" disabled={currentPage === pageCount} onClick={() => setPage((current) => Math.min(pageCount, current + 1))}>Weiter</Button>
        </div>
      </div>

      <CustomerFormDialog
        open={formOpen}
        customer={selectedCustomer}
        pending={pending}
        serverError={formError}
        onOpenChange={setFormOpen}
        onSubmit={saveCustomer}
      />

      <CustomerImportDialog
        open={importOpen}
        onOpenChange={setImportOpen}
        onCommitted={handleImportCommitted}
        onError={(message) => showToast({ type: "error", title: "Kundenimport fehlgeschlagen", description: message })}
      />

      <ConfirmDialog
        open={Boolean(deleteCustomer)}
        title="Kunde löschen"
        description="Möchten Sie den Kunden wirklich löschen?"
        pending={pending}
        onOpenChange={(open) => {
          if (!open) {
            setDeleteCustomer(null);
            setDeleteError("");
          }
        }}
        onConfirm={confirmDelete}
      >
        {deleteCustomer && (
          <dl className="grid gap-2 text-sm">
            <div className="flex justify-between gap-4">
              <dt className="text-slate-500">Kundennummer</dt>
              <dd className="font-medium">{deleteCustomer.customer_number}</dd>
            </div>
            <div className="flex justify-between gap-4">
              <dt className="text-slate-500">Firma</dt>
              <dd className="font-medium">{deleteCustomer.company_name}</dd>
            </div>
            {deleteError && <p className="text-red-600">{deleteError}</p>}
          </dl>
        )}
      </ConfirmDialog>
    </div>
  );
}
