'use client';

import { useState, useEffect, useCallback } from 'react';
import { Trash2, Plus, Save } from 'lucide-react';

import { PageHeader } from '@/components/shared/page-header';
import { ConfirmationDialog } from '@/components/shared/confirmation-dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
import { Textarea } from '@/components/ui/textarea';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Separator } from '@/components/ui/separator';
import { apiFetch } from '@/lib/api/client';
import { RecipientPicker } from './recipient-picker';
import { SUPPORTED_CURRENCIES, currencyLabel } from '@/lib/utils/currency';

interface Setting {
  key: string;
  value: unknown;
  portId: string | null;
  updatedBy: string | null;
  updatedAt: string;
}

/** Well-known settings with their display metadata */
const KNOWN_SETTINGS: Array<{
  key: string;
  label: string;
  description: string;
  type: 'boolean' | 'number' | 'json' | 'string' | 'select' | 'recipients';
  defaultValue: unknown;
  options?: Array<{ value: string; label: string }>;
}> = [
  {
    key: 'client_portal_enabled',
    label: 'Client Portal',
    description:
      'Allow clients of this port to sign in and manage their account through the client portal.',
    type: 'boolean',
    defaultValue: true,
  },
  {
    key: 'assignment_enabled',
    label: 'Interest Assignment',
    description:
      'Allow assigning interests to sales users (the "Assigned to" owner chip + auto-assign on create). Off by default - turn on only when more than one person works the pipeline. Disabling hides the assignment UI and stops auto-assigning new interests; existing assignment data is preserved and reappears if you re-enable.',
    type: 'boolean',
    defaultValue: false,
  },
  {
    key: 'tenancies_module_enabled',
    label: 'Tenancies Module',
    description:
      'Enable the per-berth tenancy tracker (lease windows, renewals, transfers). Off by default; auto-enables when the first tenancy row is created via webhook or manual add. Disabling here hides the sidebar entry and entity tabs, but never deletes underlying tenancy rows - re-enabling brings them back.',
    type: 'boolean',
    defaultValue: false,
  },
  {
    key: 'expenses_module_enabled',
    label: 'Expenses Module',
    description:
      'Enable the expenses + receipt-upload surface for this port. Disabling hides both sidebar entries (Expenses and How to upload receipts) and blocks the routes with a "module disabled" page, so bookmarks land somewhere meaningful instead of 404-ing. Previously-recorded expense rows are preserved if you re-enable.',
    type: 'boolean',
    defaultValue: true,
  },
  {
    key: 'residential_module_enabled',
    label: 'Residential Module',
    description:
      'Enable the residential (non-berth) clients + interests pipeline for this port. On by default. Disabling hides the Residential section from the sidebar and mobile nav, blocks the /residential routes with a "module disabled" page, drops residential records out of global search, and stops the public residential-inquiry endpoint from accepting new leads. Previously-recorded residential clients and interests are preserved and reappear when you re-enable.',
    type: 'boolean',
    defaultValue: true,
  },
  {
    key: 'maintenance_module_enabled',
    label: 'Berth Maintenance Module',
    description:
      'Enable the per-berth maintenance log (the "Maintenance" tab on each berth detail page). On by default. Disabling hides the Maintenance tab everywhere and blocks its log routes; previously-recorded maintenance logs are preserved and reappear when you re-enable.',
    type: 'boolean',
    defaultValue: true,
  },
  {
    key: 'ai_interest_scoring',
    label: 'AI Interest Scoring',
    description: 'Enable AI-powered interest scoring based on engagement signals',
    type: 'boolean',
    defaultValue: false,
  },
  {
    key: 'ai_email_drafts',
    label: 'AI Email Drafts',
    description: 'Enable AI-assisted email draft generation',
    type: 'boolean',
    defaultValue: false,
  },
  {
    key: 'invoice_net10_discount',
    label: 'Net-10 Invoice Discount (%)',
    description: 'Discount percentage applied when payment terms are net-10',
    type: 'number',
    defaultValue: 2,
  },
  {
    key: 'pipeline_weights',
    label: 'Pipeline Stage Weights',
    description: 'Probability weights for revenue forecast by pipeline stage (JSON)',
    type: 'json',
    defaultValue: {
      enquiry: 0.05,
      qualified: 0.15,
      nurturing: 0.15,
      eoi: 0.4,
      reservation: 0.7,
      deposit_paid: 0.85,
      contract: 0.95,
    },
  },
  {
    key: 'berth_rules',
    label: 'Berth Status Rules',
    description: 'Auto/suggest/off rules for berth status transitions (JSON)',
    type: 'json',
    defaultValue: [],
  },
  {
    key: 'default_new_interest_owner',
    label: 'Default New-Interest Owner',
    description:
      'User ID to auto-assign as the deal owner when a new interest is created. Stored as { "userId": "..." }. Leave blank to have new interests unassigned by default  -  the rep can pick an owner from the interest detail header.',
    type: 'json',
    defaultValue: { userId: null },
  },
  {
    key: 'inquiry_contact_email',
    label: 'Berth & residence reply-to email',
    description:
      'Public "reach out to us at …" address shown to clients in berth + residence inquiry confirmation emails. Defaults to sales@portnimara.com when blank.',
    type: 'string',
    defaultValue: '',
  },
  {
    key: 'contact_form_contact_email',
    label: 'Contact-form reply-to email',
    description:
      'Public "reach out to us at …" address shown to clients in contact-form confirmation emails. Defaults to hello@portnimara.com when blank.',
    type: 'string',
    defaultValue: '',
  },
  {
    key: 'inquiry_notification_recipients',
    label: 'Berth inquiry alerts',
    description:
      'Who receives staff alerts for new berth inquiries: specific users, roles, everyone with inquiry access, and/or explicit email addresses.',
    type: 'recipients',
    defaultValue: [],
  },
  {
    key: 'contact_notification_recipients',
    label: 'Contact-form alerts',
    description:
      'Who receives staff alerts for new website contact-form submissions: specific users, roles, everyone with inquiry access, and/or explicit email addresses. Falls back to Inquiry Contact Email when empty.',
    type: 'recipients',
    defaultValue: [],
  },
  {
    key: 'residential_notification_recipients',
    label: 'Residential inquiry alerts',
    description:
      'Who receives staff alerts for new residential inquiries: users, roles, everyone with inquiry access, and/or emails. Falls back to Inquiry Contact Email when empty.',
    type: 'recipients',
    defaultValue: [],
  },
  {
    key: 'signing_notification_recipients',
    label: 'Document signing alerts',
    description:
      'Who gets emailed each time a party signs an EOI / contract and when a document is fully signed: specific users, roles, everyone with inquiry access, and/or explicit email addresses. Add yourself and sales@ here. Falls back to the Reply-To address when empty.',
    type: 'recipients',
    defaultValue: [],
  },
  {
    key: 'eoi_signers',
    label: 'EOI Signers',
    description:
      'Internal staff who countersign every EOI. JSON object with `developer` (signs after the client) and `approver` (final approval). Both fields take `{ name, email }`.',
    type: 'json',
    defaultValue: {
      developer: { name: '', email: '' },
      approver: { name: '', email: '' },
    },
  },
  // ─── Berth recommender (src/lib/services/berth-recommender.service.ts) ──────
  {
    key: 'recommender_max_oversize_pct',
    label: 'Recommender  -  max oversize %',
    description:
      'Cap on how much larger a berth can be than the desired length/width/draft before it stops being suggested. Default 30.',
    type: 'number',
    defaultValue: 30,
  },
  {
    key: 'recommender_top_n_default',
    label: 'Recommender  -  default result count',
    description: 'Default number of berth recommendations returned per request. Default 8.',
    type: 'number',
    defaultValue: 8,
  },
  {
    key: 'fallthrough_policy',
    label: 'Recommender  -  fall-through policy',
    description: 'How berths re-enter the recommender after a lost deal.',
    type: 'select',
    defaultValue: 'immediate_with_heat',
    options: [
      {
        value: 'immediate_with_heat',
        label: 'Immediate (with heat boost)  -  surface again right away',
      },
      {
        value: 'cooldown',
        label: 'Cooldown  -  wait N days (see below)',
      },
      {
        value: 'never_auto_recommend',
        label: 'Never  -  only re-surface via manual rep search',
      },
    ],
  },
  {
    key: 'fallthrough_cooldown_days',
    label: 'Recommender  -  fall-through cooldown (days)',
    description:
      'Days a berth stays out of the recommender after a lost deal when the policy is `cooldown`. Default 30.',
    type: 'number',
    defaultValue: 30,
  },
  {
    key: 'heat_weight_recency',
    label: 'Heat weight  -  recency',
    description: 'Weight given to how recently the prior interest fell through. Default 30.',
    type: 'number',
    defaultValue: 30,
  },
  {
    key: 'heat_weight_furthest_stage',
    label: 'Heat weight  -  furthest stage',
    description:
      'Weight given to how close the prior interest got to closing before falling through. Default 40.',
    type: 'number',
    defaultValue: 40,
  },
  {
    key: 'heat_weight_interest_count',
    label: 'Heat weight  -  historical interest count',
    description:
      'Weight given to how often this berth has attracted interest historically. Default 15.',
    type: 'number',
    defaultValue: 15,
  },
  {
    key: 'heat_weight_eoi_count',
    label: 'Heat weight  -  historical EOI count',
    description:
      'Weight given to how often interest in this berth has reached EOI signing. Default 15.',
    type: 'number',
    defaultValue: 15,
  },
  {
    key: 'tier_ladder_hide_late_stage',
    label: 'Recommender  -  hide late-stage tier',
    description:
      'Hide berths whose only active interests are late-stage (close to closing) from recommendations.',
    type: 'boolean',
    defaultValue: true,
  },
  {
    key: 'documents_show_expired_tab',
    label: 'Documents  -  show Expired tab',
    description:
      'When off, the Expired tab on the documents hub is hidden. Use this when expired EOIs are noise that distracts reps from active deals.',
    type: 'boolean',
    defaultValue: true,
  },
  {
    key: 'berths_default_currency',
    label: 'Berths  -  default currency',
    description:
      'Currency applied to newly-created berths when none is specified on the form. Existing berths keep their per-row currency. Defaults to USD.',
    type: 'select',
    defaultValue: 'USD',
    options: SUPPORTED_CURRENCIES.map((c) => ({
      value: c.code,
      label: `${c.code}  -  ${currencyLabel(c.code)}`,
    })),
  },
];

export function SettingsManager() {
  const [portSettings, setPortSettings] = useState<Setting[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState<string | null>(null);
  const [values, setValues] = useState<Record<string, unknown>>({});
  const [customKey, setCustomKey] = useState('');
  const [customValue, setCustomValue] = useState('');

  const fetchSettings = useCallback(async () => {
    setLoading(true);
    try {
      const res = await apiFetch<{ data: { portSettings: Setting[]; globalSettings: Setting[] } }>(
        '/api/v1/admin/settings',
      );
      setPortSettings(res.data.portSettings);

      // Build values map from existing settings
      const vals: Record<string, unknown> = {};
      for (const s of res.data.portSettings) {
        vals[s.key] = s.value;
      }
      setValues(vals);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    // Initial settings load on mount.
    // eslint-disable-next-line react-hooks/set-state-in-effect
    void fetchSettings();
  }, [fetchSettings]);

  async function saveSetting(key: string, value: unknown) {
    setSaving(key);
    try {
      await apiFetch('/api/v1/admin/settings', {
        method: 'PUT',
        body: { key, value },
      });
      await fetchSettings();
    } finally {
      setSaving(null);
    }
  }

  async function handleDeleteSetting(key: string) {
    await apiFetch('/api/v1/admin/settings', {
      method: 'DELETE',
      body: { key },
    });
    await fetchSettings();
  }

  async function handleAddCustom() {
    if (!customKey.trim()) return;
    let parsed: unknown;
    try {
      parsed = JSON.parse(customValue);
    } catch {
      parsed = customValue;
    }
    await saveSetting(customKey, parsed);
    setCustomKey('');
    setCustomValue('');
  }

  function getEffectiveValue(key: string, defaultValue: unknown): unknown {
    return values[key] ?? defaultValue;
  }

  if (loading) {
    return (
      <div>
        <PageHeader title="System Settings" description="Configure system behavior for this port" />
        <div className="flex items-center justify-center py-12 text-muted-foreground">
          Loading...
        </div>
      </div>
    );
  }

  // Custom settings = port settings that aren't in KNOWN_SETTINGS
  const knownKeys = new Set(KNOWN_SETTINGS.map((s) => s.key));
  const customSettings = portSettings.filter((s) => !knownKeys.has(s.key));

  return (
    <div>
      <PageHeader title="System Settings" description="Configure system behavior for this port" />

      <div className="space-y-6 mt-6">
        {/* Feature Flags */}
        <Card>
          <CardHeader>
            <CardTitle>Feature Flags</CardTitle>
            <CardDescription>Enable or disable optional features</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {KNOWN_SETTINGS.filter((s) => s.type === 'boolean').map((setting) => (
              <div key={setting.key} className="flex items-center justify-between">
                <div>
                  <Label>{setting.label}</Label>
                  <p className="text-xs text-muted-foreground">{setting.description}</p>
                </div>
                <Switch
                  checked={getEffectiveValue(setting.key, setting.defaultValue) === true}
                  disabled={saving === setting.key}
                  onCheckedChange={(checked) => saveSetting(setting.key, checked)}
                />
              </div>
            ))}
          </CardContent>
        </Card>

        {/* String + Select Settings  -  both render in the same card.
            'select' settings get a Select dropdown bound to setting.options;
            'string' settings get a free-text Input. */}
        {KNOWN_SETTINGS.some((s) => s.type === 'string' || s.type === 'select') && (
          <Card>
            <CardHeader>
              <CardTitle>Inquiry Settings</CardTitle>
              <CardDescription>Configure inquiry notification behavior</CardDescription>
            </CardHeader>
            <CardContent className="space-y-4">
              {KNOWN_SETTINGS.filter((s) => s.type === 'string' || s.type === 'select').map(
                (setting) => (
                  <div
                    key={setting.key}
                    // Stack label/description above the input on phone widths.
                    // The previous flex row crushed the label column into a
                    // narrow vertical stripe ("Inquiry / Contact / Email" wrapping
                    // one word per line) while the input took the rest.
                    className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4"
                  >
                    <div className="flex-1">
                      <Label>{setting.label}</Label>
                      <p className="text-xs text-muted-foreground">{setting.description}</p>
                    </div>
                    <div className="flex items-center gap-2">
                      {setting.type === 'select' && setting.options ? (
                        <Select
                          value={String(getEffectiveValue(setting.key, setting.defaultValue) ?? '')}
                          onValueChange={(v) =>
                            setValues((prev) => ({ ...prev, [setting.key]: v }))
                          }
                        >
                          <SelectTrigger className="w-full sm:w-72">
                            <SelectValue />
                          </SelectTrigger>
                          <SelectContent>
                            {setting.options.map((opt) => (
                              <SelectItem key={opt.value} value={opt.value}>
                                {opt.label}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                      ) : (
                        <Input
                          type="text"
                          className="w-full sm:w-64"
                          value={String(getEffectiveValue(setting.key, setting.defaultValue) ?? '')}
                          onChange={(e) =>
                            setValues((prev) => ({
                              ...prev,
                              [setting.key]: e.target.value,
                            }))
                          }
                        />
                      )}
                      <Button
                        size="sm"
                        variant="outline"
                        disabled={saving === setting.key}
                        onClick={() =>
                          saveSetting(setting.key, values[setting.key] ?? setting.defaultValue)
                        }
                      >
                        <Save className="h-3.5 w-3.5" aria-hidden />
                      </Button>
                    </div>
                  </div>
                ),
              )}
            </CardContent>
          </Card>
        )}

        {/* Notification Recipients (users / roles / everyone / emails) */}
        {KNOWN_SETTINGS.some((s) => s.type === 'recipients') && (
          <Card>
            <CardHeader>
              <CardTitle>Notification Recipients</CardTitle>
              <CardDescription>
                Who receives staff alerts for new inquiries. Pick specific users, roles, everyone
                with inquiry access, and/or extra email addresses.
              </CardDescription>
            </CardHeader>
            <CardContent className="space-y-6">
              {KNOWN_SETTINGS.filter((s) => s.type === 'recipients').map((setting) => (
                <div key={setting.key} className="space-y-2">
                  <Label>{setting.label}</Label>
                  <p className="text-xs text-muted-foreground">{setting.description}</p>
                  <RecipientPicker
                    value={getEffectiveValue(setting.key, setting.defaultValue)}
                    saving={saving === setting.key}
                    onSave={(config) => saveSetting(setting.key, config)}
                  />
                </div>
              ))}
            </CardContent>
          </Card>
        )}

        {/* Numeric Settings */}
        <Card>
          <CardHeader>
            <CardTitle>Business Rules</CardTitle>
            <CardDescription>Configure financial and operational parameters</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {KNOWN_SETTINGS.filter((s) => s.type === 'number').map((setting) => (
              <div
                key={setting.key}
                className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-4"
              >
                <div className="flex-1">
                  <Label>{setting.label}</Label>
                  <p className="text-xs text-muted-foreground">{setting.description}</p>
                </div>
                <div className="flex items-center gap-2">
                  <Input
                    type="number"
                    className="w-full sm:w-24"
                    value={String(getEffectiveValue(setting.key, setting.defaultValue) ?? '')}
                    onChange={(e) =>
                      setValues((prev) => ({
                        ...prev,
                        [setting.key]: parseFloat(e.target.value) || 0,
                      }))
                    }
                  />
                  <Button
                    size="sm"
                    variant="outline"
                    disabled={saving === setting.key}
                    onClick={() =>
                      saveSetting(setting.key, values[setting.key] ?? setting.defaultValue)
                    }
                  >
                    <Save className="h-3.5 w-3.5" aria-hidden />
                  </Button>
                </div>
              </div>
            ))}
          </CardContent>
        </Card>

        {/* JSON Settings */}
        <Card>
          <CardHeader>
            <CardTitle>Advanced Configuration</CardTitle>
            <CardDescription>
              JSON-based settings for pipeline weights and berth rules
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-6">
            {KNOWN_SETTINGS.filter((s) => s.type === 'json').map((setting) => {
              const currentValue = getEffectiveValue(setting.key, setting.defaultValue);
              const jsonStr =
                values[`${setting.key}_edit`] !== undefined
                  ? String(values[`${setting.key}_edit`])
                  : JSON.stringify(currentValue, null, 2);
              return (
                <div key={setting.key} className="space-y-2">
                  <Label>{setting.label}</Label>
                  <p className="text-xs text-muted-foreground">{setting.description}</p>
                  <Textarea
                    className="font-mono text-xs"
                    rows={6}
                    value={jsonStr}
                    onChange={(e) =>
                      setValues((prev) => ({ ...prev, [`${setting.key}_edit`]: e.target.value }))
                    }
                  />
                  <Button
                    size="sm"
                    disabled={saving === setting.key}
                    onClick={() => {
                      try {
                        const parsed = JSON.parse(
                          String(values[`${setting.key}_edit`] ?? JSON.stringify(currentValue)),
                        );
                        void saveSetting(setting.key, parsed);
                      } catch {
                        // invalid JSON - do nothing
                      }
                    }}
                  >
                    {saving === setting.key ? 'Saving…' : 'Save'}
                  </Button>
                </div>
              );
            })}
          </CardContent>
        </Card>

        {/* Custom Settings */}
        <Card>
          <CardHeader>
            <CardTitle>Custom Settings</CardTitle>
            <CardDescription>
              Free-form key-value entries that aren&apos;t covered by the typed forms above. Use
              this for one-off feature flags, integration secrets, or experimental tunables that the
              platform reads at runtime via{' '}
              <code className="text-xs">getSystemSetting(portId, key)</code>. Values can be JSON
              objects, plain strings, numbers, or booleans. Most reps will never need this section -
              touch only if you know which key affects what.
            </CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {customSettings.map((setting) => (
              <div key={setting.key} className="flex items-center justify-between gap-2">
                <div>
                  <code className="text-sm font-mono">{setting.key}</code>
                  <p className="text-xs text-muted-foreground">
                    {typeof setting.value === 'object'
                      ? JSON.stringify(setting.value)
                      : String(setting.value)}
                  </p>
                </div>
                <ConfirmationDialog
                  trigger={
                    <Button
                      variant="ghost"
                      size="sm"
                      className="text-destructive hover:text-destructive"
                    >
                      <Trash2 className="h-4 w-4" aria-hidden />
                    </Button>
                  }
                  title="Delete Setting"
                  description={`Delete "${setting.key}"? This may affect system behavior.`}
                  confirmLabel="Delete"
                  onConfirm={() => handleDeleteSetting(setting.key)}
                />
              </div>
            ))}

            <Separator />

            <div className="flex gap-2">
              <Input
                placeholder="Key"
                value={customKey}
                onChange={(e) => setCustomKey(e.target.value)}
                className="w-40"
              />
              <Input
                placeholder="Value (JSON or string)"
                value={customValue}
                onChange={(e) => setCustomValue(e.target.value)}
                className="flex-1"
              />
              <Button variant="outline" onClick={handleAddCustom} disabled={!customKey.trim()}>
                <Plus className="mr-1 h-4 w-4" aria-hidden />
                Add
              </Button>
            </div>
          </CardContent>
        </Card>
      </div>
    </div>
  );
}
