"use client";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { DataTable } from "@/components/shared/data-table";
import { Field, SelectField, TextareaField } from "@/components/shared/field";
import { StatusBadge } from "@/components/shared/page";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { recentDateTime } from "@/lib/format";
import { DeleteDialog, Editor } from "./editor";
import { submitPricingMutation } from "./pricing-client";
import type {
  CreateSchedulePayload,
  CreateScheduleTargetPayload,
  PricingCatalog,
  ScheduleAssignment,
  RateSchedule,
  ScheduleTarget,
  TariffSummary,
} from "./api-contract";
import { groupScheduleAssignmentsByLocation } from "./pricing-view";

const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const timePattern = /^([01]\d|2[0-3]):[0-5]\d$/;

type ScheduleRow = RateSchedule & {
  status: "Active" | "Inactive";
  defaultTariffName: string;
  targetCount: number;
  assignedLocationSummary: string;
};

function ScheduleAssignmentsSummary({
  assignments,
}: {
  assignments?: readonly ScheduleAssignment[];
}) {
  if (assignments === undefined) {
    return <span className="text-muted-foreground">Not returned</span>;
  }

  const locations = groupScheduleAssignmentsByLocation(assignments);
  if (locations.length === 0) {
    return <span className="text-muted-foreground">No locations assigned</span>;
  }

  return (
    <ul className="space-y-1">
      {locations.map((location) => (
        <li className="flex flex-wrap items-center gap-x-2" key={location.locationId}>
          <span className="font-medium">{location.locationName}</span>
          <span className="text-xs text-muted-foreground">
            {location.assignments.length} {location.assignments.length === 1 ? "connector" : "connectors"}
          </span>
        </li>
      ))}
    </ul>
  );
}

export function ScheduleAssignmentsList({
  assignments,
}: {
  assignments?: readonly ScheduleAssignment[];
}) {
  if (assignments === undefined) {
    return (
      <p className="text-sm text-muted-foreground">
        Assignment data was not returned by the API.
      </p>
    );
  }

  const locations = groupScheduleAssignmentsByLocation(assignments);
  if (locations.length === 0) {
    return <p className="text-sm text-muted-foreground">No locations are assigned to this schedule.</p>;
  }

  return (
    <div className="space-y-3">
      {locations.map((location) => (
        <section className="rounded-lg border p-3" key={location.locationId}>
          <div className="mb-2 flex flex-wrap items-center justify-between gap-2">
            <h4 className="font-medium">{location.locationName}</h4>
            <span className="text-xs text-muted-foreground">
              {location.assignments.length} {location.assignments.length === 1 ? "connector" : "connectors"}
            </span>
          </div>
          <ul className="divide-y">
            {location.assignments.map((assignment) => (
              <li className="flex flex-wrap items-center justify-between gap-2 py-2 text-sm" key={assignment.id}>
                <div className="min-w-0">
                  <p className="font-medium">{assignment.chargepoint_name?.trim() || `Charge point ${assignment.chargepoint_id.slice(0, 8)}`}</p>
                  <p className="text-muted-foreground">
                    {assignment.connector_name?.trim() || `Connector ${assignment.connector_number}`}
                  </p>
                </div>
                <StatusBadge>{assignment.active ? "Active" : "Inactive"}</StatusBadge>
              </li>
            ))}
          </ul>
        </section>
      ))}
    </div>
  );
}

function ScheduleError({ message, retry }: { message: string; retry: () => void }) {
  return (
    <section className="panel flex flex-col items-start gap-3 p-6 sm:flex-row sm:items-center sm:justify-between">
      <div role="alert">
        <h2 className="font-semibold">Schedules are unavailable</h2>
        <p className="mt-1 text-sm text-muted-foreground">{message}</p>
      </div>
      <Button variant="outline" onClick={retry}>Try again</Button>
    </section>
  );
}

export function RateSchedules({
  catalog,
  manage,
  onOpenDetail,
  onOpenTarget,
  onRefresh,
  onNotice,
}: {
  catalog: PricingCatalog;
  manage: boolean;
  onOpenDetail: (scheduleId: string) => void;
  onOpenTarget: (targetId: string) => void;
  onRefresh: () => void;
  onNotice: (message: string) => void;
}) {
  const router = useRouter();
  const [createOpen, setCreateOpen] = useState(false);
  const [createError, setCreateError] = useState("");
  const [creating, setCreating] = useState(false);
  const [managingSchedule, setManagingSchedule] = useState<RateSchedule | null>(null);
  const [removingSchedule, setRemovingSchedule] = useState<RateSchedule | null>(null);
  const [deleteError, setDeleteError] = useState("");
  const [deleting, setDeleting] = useState(false);
  const tariffs = catalog.tariffs.data;
  const models = Array.from(new Set(tariffs.map((item) => item.commercial_model)));
  const rows: ScheduleRow[] = catalog.schedules.data.map((schedule) => ({
    ...schedule,
    status: schedule.active ? "Active" : "Inactive",
    defaultTariffName:
      tariffs.find((tariff) => tariff.id === schedule.default_tariff_id)?.name ??
      "Unavailable tariff",
    targetCount: catalog.targets.data.filter(
      (target) => target.tariff_schedule_id === schedule.id,
    ).length,
    assignedLocationSummary:
      schedule.assignments === undefined
        ? "Assignment data not returned"
        : groupScheduleAssignmentsByLocation(schedule.assignments)
            .map((location) => location.locationName)
            .join(" "),
  }));

  async function createSchedule(payload: CreateSchedulePayload) {
    setCreating(true);
    setCreateError("");
    const error = await submitPricingMutation("/api/pricing/schedules", "POST", payload);
    setCreating(false);
    if (error) {
      setCreateError(error);
      return;
    }
    setCreateOpen(false);
    onNotice("Schedule created successfully.");
    router.refresh();
  }

  async function deleteSchedule() {
    if (!removingSchedule) return;
    setDeleting(true);
    setDeleteError("");
    const error = await submitPricingMutation(
      `/api/pricing/schedules/${encodeURIComponent(removingSchedule.id)}`,
      "DELETE",
    );
    setDeleting(false);
    if (error) {
      setDeleteError(error);
      return;
    }
    setRemovingSchedule(null);
    onNotice("Schedule deleted successfully.");
    router.refresh();
  }

  if (catalog.schedules.error)
    return <ScheduleError message={catalog.schedules.error} retry={onRefresh} />;

  return (
    <div className="space-y-4">
      {catalog.targets.error && (
        <p role="alert" className="rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive">
          Schedule target data could not be loaded. The schedule list is still available; refresh before changing target windows.
        </p>
      )}
      {catalog.tariffs.error && (
        <p role="alert" className="rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive">
          Tariff options could not be loaded. Creating schedules and target windows is unavailable until the tariff list is restored.
        </p>
      )}
      {!catalog.tariffs.error && tariffs.length > 0 && !tariffs.some((tariff) => tariff.active) && (
        <p role="status" className="rounded-lg border bg-muted/40 p-3 text-sm text-muted-foreground">
          Create or activate a tariff before adding a schedule.
        </p>
      )}
      <DataTable
        title="Charging schedules"
        description="Choose a default tariff, then set the weekly windows that use other tariffs. Times use the schedule timezone."
        rows={rows}
        searchPlaceholder="Search schedules..."
        emptyMessage="No schedules are configured yet. Create a schedule to get started."
        filters={[{ key: "status", label: "Status", options: ["Active", "Inactive"] }]}
        columns={[
          { key: "name", label: "Schedule" },
          { key: "code", label: "Code" },
          { key: "defaultTariffName", label: "Default tariff" },
          {
            key: "assignedLocationSummary",
            label: "Assigned locations",
            render: (row) => <ScheduleAssignmentsSummary assignments={row.assignments} />,
            exportValue: (row) =>
              row.assignments === undefined
                ? "Assignment data not returned"
                : groupScheduleAssignmentsByLocation(row.assignments)
                    .map((location) => `${location.locationName} (${location.assignments.length})`)
                    .join(", ") || "No locations assigned",
          },
          { key: "targetCount", label: "Windows" },
          { key: "timezone", label: "Timezone" },
          { key: "status", label: "Status", render: (row) => <StatusBadge>{row.status}</StatusBadge> },
          { key: "updated_at", label: "Updated", render: (row) => recentDateTime(row.updated_at) },
        ]}
        onRefresh={onRefresh}
        onCreate={manage && tariffs.some((tariff) => tariff.active) ? () => { setCreateError(""); setCreateOpen(true); } : undefined}
        createLabel="Create schedule"
        actions={(row) => (
          <div className="flex flex-wrap gap-2">
            <Button size="sm" variant="outline" onClick={() => onOpenDetail(row.id)}>Details</Button>
            {manage && (
              <>
                <Button size="sm" onClick={() => setManagingSchedule(row)}>Manage targets</Button>
                <Button size="sm" variant="ghost" onClick={() => { setDeleteError(""); setRemovingSchedule(row); }}>Delete</Button>
              </>
            )}
          </div>
        )}
      />
      {manage && createOpen && (
        <CreateScheduleDialog
          tariffs={tariffs}
          models={models}
          error={createError}
          submitting={creating}
          onClose={() => setCreateOpen(false)}
          onSubmit={createSchedule}
        />
      )}
      {manage && managingSchedule && (
        <ManageTargetsDialog
          schedule={managingSchedule}
          catalog={catalog}
          onClose={() => setManagingSchedule(null)}
          onOpenDetail={(id) => {
            setManagingSchedule(null);
            onOpenTarget(id);
          }}
          onNotice={onNotice}
        />
      )}
      {manage && removingSchedule && (
        <DeleteDialog
          name={removingSchedule.name}
          title="Delete charging schedule"
          description="This operation is sent to the TIAR API."
          confirmation={<p>Delete <strong>{removingSchedule.name}</strong>?</p>}
          submitLabel={deleting ? "Deleting…" : "Delete schedule"}
          submitting={deleting}
          error={deleteError}
          onClose={() => setRemovingSchedule(null)}
          onConfirm={deleteSchedule}
        />
      )}
    </div>
  );
}

function CreateScheduleDialog({
  tariffs,
  models,
  error,
  submitting,
  onClose,
  onSubmit,
}: {
  tariffs: readonly TariffSummary[];
  models: readonly string[];
  error: string;
  submitting: boolean;
  onClose: () => void;
  onSubmit: (payload: CreateSchedulePayload) => void;
}) {
  const activeTariffs = tariffs.filter((tariff) => tariff.active);
  const initialTariff = activeTariffs[0];
  const [code, setCode] = useState("");
  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const [defaultTariffId, setDefaultTariffId] = useState(initialTariff?.id ?? "");
  const [commercialModel, setCommercialModel] = useState(initialTariff?.commercial_model ?? models[0] ?? "B2C");
  const [timezone, setTimezone] = useState("Asia/Jakarta");
  const [active, setActive] = useState(true);
  return (
    <Editor
      open
      title="Create charging schedule"
      description="Set the default tariff and timezone. Add weekly target windows after saving."
      submitLabel="Create schedule"
      submitting={submitting}
      error={error}
      onClose={onClose}
      onSubmit={() => onSubmit({
        code,
        name,
        description,
        default_tariff_id: defaultTariffId,
        commercial_model: commercialModel,
        timezone,
        active,
      })}
    >
      <div className="grid gap-4 sm:grid-cols-2">
        <Field label="Schedule code" required maxLength={255} value={code} onChange={(event) => setCode(event.target.value)} />
        <Field label="Schedule name" required maxLength={255} value={name} onChange={(event) => setName(event.target.value)} />
        <SelectField
          label="Default tariff"
          required
          options={[
            { value: "", label: "Select a tariff" },
            ...activeTariffs.map((tariff) => ({ value: tariff.id, label: tariff.name })),
          ]}
          value={defaultTariffId}
          onChange={(event) => {
            setDefaultTariffId(event.target.value);
            const selected = activeTariffs.find((tariff) => tariff.id === event.target.value);
            if (selected) setCommercialModel(selected.commercial_model);
          }}
          disabled={activeTariffs.length === 0}
        />
        <Field label="Commercial model" value={commercialModel} readOnly />
        <Field label="Timezone" required maxLength={100} value={timezone} onChange={(event) => setTimezone(event.target.value)} />
        <SelectField label="Status" options={["Active", "Inactive"]} value={active ? "Active" : "Inactive"} onChange={(event) => setActive(event.target.value === "Active")} />
      </div>
      <TextareaField label="Description" maxLength={1000} value={description} onChange={(event) => setDescription(event.target.value)} />
    </Editor>
  );
}

function ManageTargetsDialog({
  schedule,
  catalog,
  onClose,
  onOpenDetail,
  onNotice,
}: {
  schedule: RateSchedule;
  catalog: PricingCatalog;
  onClose: () => void;
  onOpenDetail: (targetId: string) => void;
  onNotice: (message: string) => void;
}) {
  const router = useRouter();
  const [tariffId, setTariffId] = useState("");
  const [day, setDay] = useState("");
  const [startTime, setStartTime] = useState("");
  const [endTime, setEndTime] = useState("");
  const [targetStatus, setTargetStatus] = useState<"Active" | "Inactive" | "">("");
  const [createError, setCreateError] = useState("");
  const [creating, setCreating] = useState(false);
  const [removing, setRemoving] = useState<ScheduleTarget | null>(null);
  const [deleteError, setDeleteError] = useState("");
  const [deleting, setDeleting] = useState(false);
  const eligibleTariffs = catalog.tariffs.data.filter(
    (tariff) => tariff.active && tariff.commercial_model === schedule.commercial_model,
  );
  const targets = catalog.targets.data.filter(
    (target) => target.tariff_schedule_id === schedule.id,
  );
  const selectedTariff = eligibleTariffs.find((tariff) => tariff.id === tariffId);

  async function createTarget() {
    if (
      !selectedTariff ||
      !day ||
      !targetStatus ||
      !timePattern.test(startTime) ||
      !timePattern.test(endTime) ||
      startTime >= endTime
    ) {
      setCreateError("Select a tariff, day, and status, then enter a valid time range.");
      return;
    }
    setCreating(true);
    setCreateError("");
    const payload: CreateScheduleTargetPayload = {
      tariff_id: tariffId,
      day_of_week: Number(day),
      start_time: `${startTime}:00`,
      end_time: `${endTime}:00`,
      active: targetStatus === "Active",
    };
    const error = await submitPricingMutation(
      `/api/pricing/schedules/${encodeURIComponent(schedule.id)}/targets`,
      "POST",
      payload,
    );
    setCreating(false);
    if (error) {
      setCreateError(error);
      return;
    }
    setTariffId("");
    setDay("");
    setStartTime("");
    setEndTime("");
    setTargetStatus("");
    onNotice("Schedule target created successfully.");
    router.refresh();
  }

  async function deleteTarget() {
    if (!removing) return;
    setDeleting(true);
    setDeleteError("");
    const error = await submitPricingMutation(
      `/api/pricing/schedule-targets/${encodeURIComponent(removing.id)}`,
      "DELETE",
    );
    setDeleting(false);
    if (error) {
      setDeleteError(error);
      return;
    }
    setRemoving(null);
    onNotice("Schedule target deleted successfully.");
    router.refresh();
  }

  return (
    <>
      <Dialog open onOpenChange={(value) => !value && onClose()}>
        <DialogContent className="max-h-[90vh] overflow-y-auto">
          <DialogHeader>
            <DialogTitle>Manage targets · {schedule.name}</DialogTitle>
            <DialogDescription>
              Add or remove weekly tariff windows. The schedule uses {schedule.timezone}.
            </DialogDescription>
          </DialogHeader>
          {catalog.targets.error ? (
            <p role="alert" className="rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive">{catalog.targets.error}</p>
          ) : targets.length ? (
            <div className="space-y-2">
              {targets.map((target) => (
                <div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border p-3" key={target.id}>
                  <div>
                    <p className="text-sm font-medium">{days[target.day_of_week]} · {target.start_time.slice(0, 5)}–{target.end_time.slice(0, 5)}</p>
                    <p className="mt-1 text-xs text-muted-foreground">{catalog.tariffs.data.find((tariff) => tariff.id === target.tariff_id)?.name ?? "Unavailable tariff"} · {target.active ? "Active" : "Inactive"}</p>
                  </div>
                  <div className="flex gap-2">
                    <Button size="sm" variant="outline" onClick={() => onOpenDetail(target.id)}>Details</Button>
                    <Button size="sm" variant="ghost" onClick={() => { setDeleteError(""); setRemoving(target); }}>Delete</Button>
                  </div>
                </div>
              ))}
            </div>
          ) : (
            <p className="rounded-lg border border-dashed p-4 text-sm text-muted-foreground">No weekly targets yet. Add the first window below.</p>
          )}
          <section className="space-y-3 border-t pt-4">
            <div>
              <h3 className="font-semibold">Add weekly target</h3>
              <p className="mt-1 text-xs text-muted-foreground">Targets must start and end on the same day.</p>
            </div>
            {eligibleTariffs.length === 0 ? (
              <p role="alert" className="text-sm text-destructive">No active {schedule.commercial_model} tariffs are available for this schedule.</p>
            ) : (
              <div className="grid gap-3 sm:grid-cols-2">
                <SelectField
                  label="Tariff"
                  required
                  options={[
                    { value: "", label: "Select a tariff" },
                    ...eligibleTariffs.map((tariff) => ({ value: tariff.id, label: tariff.name })),
                  ]}
                  value={tariffId}
                  onChange={(event) => {
                    setTariffId(event.target.value);
                    setCreateError("");
                  }}
                />
                <SelectField
                  label="Day of week"
                  required
                  options={[
                    { value: "", label: "Select a day" },
                    ...days.map((label, index) => ({ value: String(index), label })),
                  ]}
                  value={day}
                  onChange={(event) => {
                    setDay(event.target.value);
                    setCreateError("");
                  }}
                />
                <Field
                  label="Start time"
                  type="time"
                  required
                  value={startTime}
                  onChange={(event) => {
                    setStartTime(event.target.value);
                    setCreateError("");
                  }}
                />
                <Field
                  label="End time"
                  type="time"
                  required
                  value={endTime}
                  onChange={(event) => {
                    setEndTime(event.target.value);
                    setCreateError("");
                  }}
                />
                <SelectField
                  label="Status"
                  required
                  options={[
                    { value: "", label: "Select a status" },
                    "Active",
                    "Inactive",
                  ]}
                  value={targetStatus}
                  onChange={(event) => {
                    setTargetStatus(event.target.value as "Active" | "Inactive" | "");
                    setCreateError("");
                  }}
                />
              </div>
            )}
            {createError && <p role="alert" className="text-sm text-destructive">{createError}</p>}
            <div className="flex justify-end">
              <Button onClick={createTarget} disabled={creating || !eligibleTariffs.length || !!catalog.targets.error}>
                {creating ? "Saving…" : "Add target"}
              </Button>
            </div>
          </section>
        </DialogContent>
      </Dialog>
      {removing && (
        <DeleteDialog
          name={`${days[removing.day_of_week]} ${removing.start_time.slice(0, 5)}–${removing.end_time.slice(0, 5)}`}
          title="Delete schedule target"
          description="This operation is sent to the TIAR API."
          confirmation={<p>Delete this weekly target from <strong>{schedule.name}</strong>?</p>}
          submitLabel={deleting ? "Deleting…" : "Delete target"}
          submitting={deleting}
          error={deleteError}
          onClose={() => setRemoving(null)}
          onConfirm={deleteTarget}
        />
      )}
    </>
  );
}
