"use client";

import { useRef, useState } from "react";
import dynamic from "next/dynamic";
import { MapPin, ShieldCheck, UserRound, ChevronDown, Cpu } from "lucide-react";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { FormField, SelectField } from "@/components/shared/form-field";
import { SearchableFilterField } from "@/components/shared/searchable-filter-field";
import type { GoogleMapConfig } from "@/components/shared/google-map";
import { validCoordinates } from "@/lib/map-points";
import type { Location } from "@/features/locations/types";
import type { InvestorGroup, InvestorMember } from "./investor-contract";
import { createChargepoint, loadInvestorGroups, loadInvestorMembers } from "./create-client-api";
import { chargepointCreateFromForm } from "./create-contract";
import { expectsGeneratedAuthorizationKey, type CreatedChargepoint } from "./create-result";
import { ChargepointCreatedDialog } from "./chargepoint-created-dialog";

const booleanOptions = [{ value: "true", label: "Yes" }, { value: "false", label: "No" }];
const CoordinateMap = dynamic(() => import("@/components/shared/coordinate-map").then(module => module.CoordinateMap), {
  loading: () => <p role="status" className="rounded-lg border p-4 text-muted-foreground">Loading map…</p>,
});

export function CreateChargepointDialog({ open, onOpenChange, locations, mapsConfig, onCreated }: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  locations: Location[];
  mapsConfig: GoogleMapConfig;
  onCreated: (id: string) => void;
}) {
  const [locationId, setLocationId] = useState("");
  const [latitude, setLatitude] = useState("");
  const [longitude, setLongitude] = useState("");
  const [showMap, setShowMap] = useState(false);
  const [ownership, setOwnership] = useState(false);
  const [security, setSecurity] = useState(false);
  const [autoKey, setAutoKey] = useState("true");
  const [groups, setGroups] = useState<InvestorGroup[]>([]);
  const [groupId, setGroupId] = useState("");
  const [members, setMembers] = useState<InvestorMember[]>([]);
  const [ownerId, setOwnerId] = useState("");
  const [lookupLoading, setLookupLoading] = useState(false);
  const [lookupError, setLookupError] = useState("");
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState("");
  const [created, setCreated] = useState<{ result: CreatedChargepoint; name: string; identity: string }>();
  const pending = useRef(false);
  const lookupVersion = useRef(0);
  const errorRef = useRef<HTMLParagraphElement>(null);

  async function changeOwnership(enabled: boolean) {
    setOwnership(enabled);
    setGroupId(""); setOwnerId(""); setMembers([]); setLookupError("");
    const version = ++lookupVersion.current;
    if (!enabled) { setLookupLoading(false); return; }
    setLookupLoading(true);
    try {
      const result = await loadInvestorGroups();
      if (version === lookupVersion.current) setGroups(result);
    } catch (cause) {
      if (version === lookupVersion.current) setLookupError(cause instanceof Error ? cause.message : "Unable to load investor groups.");
    } finally {
      if (version === lookupVersion.current) setLookupLoading(false);
    }
  }
  async function changeGroup(id: string) {
    setGroupId(id); setOwnerId(""); setMembers([]); setLookupError("");
    const version = ++lookupVersion.current;
    if (!id) { setLookupLoading(false); return; }
    setLookupLoading(true);
    try {
      const result = await loadInvestorMembers(id);
      if (version === lookupVersion.current) setMembers(result);
    } catch (cause) {
      if (version === lookupVersion.current) setLookupError(cause instanceof Error ? cause.message : "Unable to load investor emails.");
    } finally {
      if (version === lookupVersion.current) setLookupLoading(false);
    }
  }
  const mapLatitude = Number(latitude), mapLongitude = Number(longitude);
  const canMap = Boolean(latitude.trim() && longitude.trim() && validCoordinates(mapLatitude, mapLongitude));

  if (created) return <ChargepointCreatedDialog result={created.result} name={created.name} identity={created.identity} onContinue={() => {
    onCreated(created.result.id);
    setCreated(undefined);
    onOpenChange(false);
  }} />;

  return (
    <Dialog open={open} onOpenChange={value => { if (!pending.current) { lookupVersion.current++; onOpenChange(value); } }}>
      <DialogContent showCloseButton={!saving} overlayClassName="supports-backdrop-filter:backdrop-blur-none" className="flex max-h-[92dvh] flex-col gap-0 overflow-clip p-0 sm:max-w-[880px]">
        <DialogHeader className="shrink-0 border-b px-6 py-5 pr-14">
          <DialogTitle>Create chargepoint</DialogTitle>
          <DialogDescription>Set up the station and its location. Ownership and security settings are optional.</DialogDescription>
        </DialogHeader>
        <form className="flex min-h-0 flex-1 flex-col" onSubmit={async event => {
          event.preventDefault();
          if (pending.current) return;
          setError("");
          try {
            if (!locations.some(location => location.id === locationId)) throw new Error("Select a location from the list.");
            if (ownership && (!groupId || !members.some(member => member.id === ownerId))) throw new Error("Select an investor group and an email from that group, or turn off ownership.");
            const payload = chargepointCreateFromForm(new FormData(event.currentTarget), locationId, ownership, security);
            pending.current = true; setSaving(true);
            const created = await createChargepoint(payload, groupId);
            if (expectsGeneratedAuthorizationKey(payload)) {
              setCreated({ result: { ...created, ...(!created.authorizationKey ? { authorizationKeyMissing: true } : {}) }, name: payload.name, identity: payload.ocpp_identity });
            } else {
              onCreated(created.id);
              onOpenChange(false);
            }
          } catch (cause) {
            setError(cause instanceof Error ? cause.message : "Unable to create this chargepoint. Please try again.");
            requestAnimationFrame(() => errorRef.current?.focus());
          } finally { pending.current = false; setSaving(false); }
        }}>
          <div className="min-h-0 flex-1 space-y-5 overflow-y-auto px-6 py-5">
            {error && <p ref={errorRef} tabIndex={-1} role="alert" className="rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive">{error}</p>}
            <fieldset disabled={saving} className="space-y-5 disabled:opacity-70">
              <section className="rounded-xl border p-4 sm:p-5" aria-labelledby="station-information">
                <h3 id="station-information" className="mb-4 font-semibold">Station information</h3>
                <div className="grid gap-4 sm:grid-cols-2">
                  <FormField name="name" label="Chargepoint name" placeholder="e.g. Rumanami Charger 003" required maxLength={256} />
                  <SelectField name="protocol" label="Protocol" options={[{ value: "ocpp1.6", label: "OCPP 1.6" }, { value: "ocpp2.0.1", label: "OCPP 2.0.1" }]} />
                  <FormField name="ocpp_identity" label="OCPP identity" placeholder="e.g. CP-RUMANAMI-003" required maxLength={256} />
                  <FormField name="static_endpoint" label="Static endpoint" placeholder="e.g. CP-RUMANAMI-003" required maxLength={256} />
                  <FormField className="sm:col-span-2" name="description" label="Description" placeholder="Station purpose or installation notes" maxLength={2000} />
                  <FormField className="sm:col-span-2" name="connection_url" label="Connection URL" placeholder="wss://your-csms/cms/CP-RUMANAMI-003" maxLength={512} />
                  <SelectField name="active" label="Active" options={booleanOptions} />
                  <SelectField name="public" label="Public access" options={booleanOptions} />
                  <SelectField name="is_simulator" label="Station type" options={[{ value: "false", label: "Physical station" }, { value: "true", label: "Simulator" }]} />
                  <SelectField name="status" label="Initial status" options={[{ value: "available", label: "Available" }, { value: "unavailable", label: "Unavailable" }]} />
                  <SelectField name="enable_authorization" label="Charging authorization required" options={[{ value: "false", label: "No" }, { value: "true", label: "Yes" }]} />
                </div>
              </section>
              <section className="rounded-xl border p-4 sm:p-5" aria-labelledby="station-location">
                <h3 id="station-location" className="mb-4 flex items-center gap-2 font-semibold"><MapPin aria-hidden="true" className="size-4" /> Location</h3>
                <SearchableFilterField name="location_id" label="Location" required value={locationId} allowCustomValue={false} options={locations.map(location => ({ value: location.id, label: location.name, description: location.address }))} onValueChange={id => {
                  setLocationId(id);
                  const location = locations.find(location => location.id === id);
                  if (location) { setLatitude(String(location.latitude)); setLongitude(String(location.longitude)); }
                }} />
                {!locations.length && <p className="mt-2 text-sm text-muted-foreground">No locations are available. Create a location first or refresh the list.</p>}
                <p className="mt-2 text-xs text-muted-foreground">The selected location supplies the initial coordinates. Adjust them for the station’s exact position.</p>
                <div className="mt-4 grid gap-4 sm:grid-cols-2">
                  <FormField name="latitude" label="Latitude" type="number" required min={-90} max={90} step="any" value={latitude} onChange={event => setLatitude(event.target.value)} />
                  <FormField name="longitude" label="Longitude" type="number" required min={-180} max={180} step="any" value={longitude} onChange={event => setLongitude(event.target.value)} />
                </div>
                <Button type="button" variant="outline" className="mt-4" aria-expanded={showMap} disabled={!canMap} onClick={() => setShowMap(value => !value)}><MapPin />{showMap ? "Hide map" : "Adjust position on map"}</Button>
                {showMap && canMap && <div className="mt-4 space-y-2"><p className="text-xs text-muted-foreground">Click the map or drag the pin to update coordinates.</p><CoordinateMap config={mapsConfig} latitude={mapLatitude} longitude={mapLongitude} onChange={(lat, lng) => { setLatitude(String(lat)); setLongitude(String(lng)); }} /></div>}
              </section>
              <details className="rounded-xl border p-4 sm:p-5">
                <summary className="flex cursor-pointer list-none items-center gap-2 font-semibold"><Cpu aria-hidden="true" className="size-4" /> Device details <span className="ml-auto text-xs font-normal text-muted-foreground">Vendor, serials & connectivity</span><ChevronDown className="size-4" /></summary>
                <div className="mt-4 grid gap-4 sm:grid-cols-2">
                  {[["vendor", "Vendor"], ["model", "Model"], ["firmware_version", "Firmware version"], ["box_serial_number", "Box serial number"], ["cp_serial_number", "Chargepoint serial number"], ["iccid", "ICCID"], ["imsi", "IMSI"], ["meter_serial_number", "Meter serial number"], ["meter_type", "Meter type"]].map(([name, label]) => <FormField key={name} name={name} label={label} maxLength={512} />)}
                </div>
              </details>
              <section className="rounded-xl border p-4 sm:p-5" aria-labelledby="station-ownership">
                <div className="flex items-center justify-between gap-3">
                  <div><h3 id="station-ownership" className="flex items-center gap-2 font-semibold"><UserRound aria-hidden="true" className="size-4" /> Ownership <span className="rounded-full bg-muted px-2 py-0.5 text-xs font-normal text-muted-foreground">Optional</span></h3><p className="mt-1 text-xs text-muted-foreground">Assign an investor and record their investment.</p></div>
                  <Switch aria-label="Include ownership" checked={ownership} onCheckedChange={changeOwnership} />
                </div>
                {ownership && <div className="mt-4 space-y-4">
                  <p className="text-sm text-muted-foreground">Owner type: <span className="font-medium text-foreground">Investor</span></p>
                  <SearchableFilterField name="investor_group_id" label="Investor group" required value={groupId} options={groups.map(group => ({ value: group.id, label: group.name }))} allowCustomValue={false} disabled={lookupLoading && !groupId} onValueChange={changeGroup} />
                  <SearchableFilterField name="owner_id" label="Investor email" required value={ownerId} options={members.map(member => ({ value: member.id, label: member.email }))} allowCustomValue={false} disabled={!groupId || lookupLoading} onValueChange={setOwnerId} />
                  {lookupLoading && <p role="status" className="text-sm text-muted-foreground">Loading investor options…</p>}
                  {lookupError && <div role="alert" className="text-sm text-destructive">{lookupError}<Button type="button" variant="ghost" size="sm" onClick={() => groupId ? changeGroup(groupId) : changeOwnership(true)}>Retry</Button></div>}
                  {!lookupLoading && !lookupError && !groups.length && <p role="status" className="text-sm text-muted-foreground">No investor groups are available. Leave ownership off to continue.</p>}
                  {!lookupLoading && !lookupError && groupId && !members.length && <p role="status" className="text-sm text-muted-foreground">This group has no investor emails to select.</p>}
                  <div className="grid gap-4 sm:grid-cols-3">
                    <FormField name="ownership_percentage" label="Ownership (%)" type="number" required min={0.01} max={100} step="any" defaultValue={100} />
                    <FormField name="investment_amount" label="Investment amount" type="number" required min={0} step="any" />
                    <SelectField name="currency" label="Currency" options={["IDR", "USD"]} />
                  </div>
                </div>}
              </section>
              <section className="rounded-xl border p-4 sm:p-5" aria-labelledby="station-security">
                <div className="flex items-center justify-between gap-3">
                  <div><h3 id="station-security" className="flex items-center gap-2 font-semibold"><ShieldCheck aria-hidden="true" className="size-4" /> Security <span className="rounded-full bg-muted px-2 py-0.5 text-xs font-normal text-muted-foreground">Optional</span></h3><p className="mt-1 text-xs text-muted-foreground">Configure the security profile and authorization key.</p></div>
                  <Switch aria-label="Include security" checked={security} onCheckedChange={setSecurity} />
                </div>
                {security && <div className="mt-4 grid gap-4 sm:grid-cols-2">
                  <SelectField name="security_profile" label="Security profile" options={["0", "1", "2", "3"]} />
                  <SelectField name="auto_generate_authorization_key" label="Auto-generate authorization key" options={[{ value: "true", label: "True — generate automatically" }, { value: "false", label: "False — enter manually" }]} value={autoKey} onChange={event => setAutoKey(event.target.value)} />
                  {autoKey === "false" && <div className="sm:col-span-2"><FormField name="authorization_key" label="Authorization key" type="password" autoComplete="new-password" required minLength={32} maxLength={40} /><p className="mt-1.5 text-xs text-muted-foreground">Enter 32–40 characters. The key is not saved in browser storage.</p></div>}
                </div>}
              </section>
            </fieldset>
          </div>
          <DialogFooter className="mx-0 mb-0 shrink-0 rounded-b-xl border-t px-6 py-4">
            <Button type="button" variant="outline" disabled={saving} onClick={() => onOpenChange(false)}>Cancel</Button>
            <Button type="submit" disabled={saving || !locations.length}>{saving ? "Creating…" : "Create chargepoint"}</Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}
