import React, { useEffect, useMemo, useState } from "react";
import {
  CheckCircle,
  Loader2,
  Plus,
  RotateCcw,
  Rss,
  Save,
  Trash2,
  XCircle,
} from "lucide-react";
import { newsBridge } from "../../lib/newsBridge";
import type { NewsSourceConfig } from "../../types/news";
import { ValidatedInput, type ValidationStatus } from "./ValidatedInput";

interface EditableNewsFeed extends NewsSourceConfig {
  draftKey: string;
}

interface FeedValidation {
  name?: string;
  url?: string;
  refreshMinutes?: string;
}

const createDraftKey = () => {
  if (
    typeof crypto !== "undefined" &&
    typeof crypto.randomUUID === "function"
  ) {
    return crypto.randomUUID();
  }

  return `feed-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
};

const toEditableFeed = (feed: NewsSourceConfig): EditableNewsFeed => ({
  ...feed,
  draftKey: createDraftKey(),
});

const stripDraftKeys = (feeds: EditableNewsFeed[]): NewsSourceConfig[] =>
  feeds.map(({ draftKey: _draftKey, ...feed }) => feed);

const normalizeFeedId = (value: string) =>
  value
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 48);

const createCustomFeed = (index: number): EditableNewsFeed => ({
  draftKey: createDraftKey(),
  id: `custom-feed-${index}`,
  name: "",
  url: "",
  refreshMinutes: 30,
});

const validateFeed = (feed: EditableNewsFeed): FeedValidation => {
  const validation: FeedValidation = {};
  const trimmedName = feed.name.trim();
  const trimmedUrl = feed.url.trim();

  if (!trimmedName) {
    validation.name = "Feed name is required.";
  }

  if (!trimmedUrl) {
    validation.url = "Feed URL is required.";
  } else {
    try {
      const url = new URL(trimmedUrl);
      if (url.protocol !== "http:" && url.protocol !== "https:") {
        validation.url = "Feed URL must use http or https.";
      }
    } catch {
      validation.url = "Enter a valid feed URL.";
    }
  }

  if (!Number.isInteger(feed.refreshMinutes) || feed.refreshMinutes <= 0) {
    validation.refreshMinutes = "Refresh must be a positive number of minutes.";
  }

  return validation;
};

const validationStatus = (error?: string): ValidationStatus =>
  error ? "invalid" : "idle";

export const NewsFeedSettingsCard: React.FC = () => {
  const [feeds, setFeeds] = useState<EditableNewsFeed[]>([]);
  const [initialFeeds, setInitialFeeds] = useState<NewsSourceConfig[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [isResetting, setIsResetting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [success, setSuccess] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;

    const loadFeeds = async () => {
      setIsLoading(true);
      setError(null);

      try {
        const currentFeeds = await newsBridge.getNewsFeedConfig();
        if (cancelled) {
          return;
        }

        setInitialFeeds(currentFeeds);
        setFeeds(currentFeeds.map(toEditableFeed));
      } catch (loadError) {
        if (!cancelled) {
          setError(
            loadError instanceof Error
              ? loadError.message
              : "Failed to load RSS feed settings.",
          );
        }
      } finally {
        if (!cancelled) {
          setIsLoading(false);
        }
      }
    };

    void loadFeeds();

    return () => {
      cancelled = true;
    };
  }, []);

  const currentFeeds = useMemo(() => stripDraftKeys(feeds), [feeds]);
  const validations = useMemo(
    () =>
      feeds.reduce<Record<string, FeedValidation>>((map, feed) => {
        map[feed.draftKey] = validateFeed(feed);
        return map;
      }, {}),
    [feeds],
  );
  const duplicateIds = useMemo(() => {
    const counts = currentFeeds.reduce<Record<string, number>>((map, feed) => {
      map[feed.id] = (map[feed.id] ?? 0) + 1;
      return map;
    }, {});

    return new Set(
      Object.entries(counts)
        .filter(([, count]) => count > 1)
        .map(([id]) => id),
    );
  }, [currentFeeds]);
  const hasValidationErrors =
    feeds.length === 0 ||
    Object.values(validations).some(
      (validation) => Object.keys(validation).length > 0,
    ) ||
    duplicateIds.size > 0;
  const hasChanges =
    JSON.stringify(currentFeeds) !== JSON.stringify(initialFeeds);

  const updateFeed = (
    draftKey: string,
    updater: (feed: EditableNewsFeed) => EditableNewsFeed,
  ) => {
    setFeeds((current) =>
      current.map((feed) =>
        feed.draftKey === draftKey ? updater(feed) : feed,
      ),
    );
    setError(null);
    setSuccess(null);
  };

  const handleAddFeed = () => {
    setFeeds((current) => [...current, createCustomFeed(current.length + 1)]);
    setError(null);
    setSuccess(null);
  };

  const handleRemoveFeed = (draftKey: string) => {
    setFeeds((current) => current.filter((feed) => feed.draftKey !== draftKey));
    setError(null);
    setSuccess(null);
  };

  const handleDiscardChanges = () => {
    setFeeds(initialFeeds.map(toEditableFeed));
    setError(null);
    setSuccess(null);
  };

  const handleSave = async () => {
    if (hasValidationErrors) {
      setError(
        feeds.length === 0
          ? "At least one RSS feed is required."
          : "Fix the highlighted RSS feed fields before saving.",
      );
      return;
    }

    setIsSaving(true);
    setError(null);
    setSuccess(null);

    try {
      const savedFeeds = await newsBridge.saveNewsFeedConfig({
        feeds: currentFeeds,
      });
      setInitialFeeds(savedFeeds);
      setFeeds(savedFeeds.map(toEditableFeed));
      setSuccess("RSS feeds saved successfully");
    } catch (saveError) {
      setError(
        saveError instanceof Error
          ? saveError.message
          : "Failed to save RSS feeds.",
      );
    } finally {
      setIsSaving(false);
    }
  };

  const handleReset = async () => {
    setIsResetting(true);
    setError(null);
    setSuccess(null);

    try {
      const resetFeeds = await newsBridge.resetNewsFeedConfig();
      setInitialFeeds(resetFeeds);
      setFeeds(resetFeeds.map(toEditableFeed));
      setSuccess("RSS feeds reset to the default feed set");
    } catch (resetError) {
      setError(
        resetError instanceof Error
          ? resetError.message
          : "Failed to reset RSS feeds.",
      );
    } finally {
      setIsResetting(false);
    }
  };

  return (
    <section className="rounded-lg bg-term-surface p-6 shadow-sm">
      <div className="mb-6 flex items-start justify-between gap-4">
        <div className="flex-1">
          <div className="flex items-center gap-2">
            <h2 className="text-base font-mono font-semibold text-term-text">
              RSS Feeds
            </h2>
            <Rss className="h-4 w-4 text-info" />
          </div>
          <p className="mt-1.5 text-xs font-mono leading-6 text-term-text-muted">
            Customize the local-first news feed sources used by `/news`. Changes
            update the writable app config and future refresh cycles use the new
            feed list.
          </p>
        </div>
        <div className="rounded border border-term-border bg-term-bg px-3 py-2 text-right">
          <div className="text-[11px] font-mono text-term-text-muted">
            Configured feeds
          </div>
          <div className="mt-1 text-sm font-mono text-term-text">
            {feeds.length}
          </div>
        </div>
      </div>

      {isLoading ? (
        <div className="flex items-center gap-3 rounded-lg border border-[var(--term-status-info-border)] bg-[var(--term-status-info)] px-4 py-4 text-sm font-mono text-[var(--term-status-info-strong)]">
          <Loader2 className="h-4 w-4 animate-spin" />
          Loading RSS feed settings...
        </div>
      ) : (
        <>
          <div className="space-y-4">
            {feeds.map((feed, index) => {
              const feedValidation = validations[feed.draftKey] ?? {};
              const feedId = duplicateIds.has(feed.id)
                ? `${feed.id} (duplicate id)`
                : feed.id;

              return (
                <article
                  key={feed.draftKey}
                  className="rounded-lg border border-term-border-subtle bg-term-bg p-4"
                >
                  <div className="mb-4 flex items-start justify-between gap-4">
                    <div>
                      <div className="text-xs font-mono uppercase tracking-[0.18em] text-term-text-tertiary">
                        Feed {index + 1}
                      </div>
                      <div className="mt-1 font-mono text-xs text-info">
                        {feedId}
                      </div>
                    </div>
                    <button
                      type="button"
                      onClick={() => handleRemoveFeed(feed.draftKey)}
                      className="rounded border border-[var(--term-status-error-border)] bg-[var(--term-status-error)] px-3 py-2 text-xs font-mono text-negative transition-colors hover:border-negative hover:brightness-110"
                    >
                      <span className="inline-flex items-center gap-2">
                        <Trash2 className="h-3.5 w-3.5" />
                        Remove
                      </span>
                    </button>
                  </div>

                  <div className="grid gap-4 lg:grid-cols-[1.1fr_1.6fr_160px]">
                    <ValidatedInput
                      label="Feed Name"
                      value={feed.name}
                      onChange={(event) => {
                        const nextName = event.target.value;
                        updateFeed(feed.draftKey, (current) => {
                          const nextId =
                            current.id.startsWith("custom-feed-") &&
                            nextName.trim()
                              ? normalizeFeedId(nextName) || current.id
                              : current.id;
                          return {
                            ...current,
                            id: nextId,
                            name: nextName,
                          };
                        });
                      }}
                      placeholder="Federal Reserve Press Releases"
                      validationStatus={validationStatus(feedValidation.name)}
                      errorMessage={feedValidation.name}
                      disabled={isSaving || isResetting}
                    />
                    <ValidatedInput
                      label="Feed URL"
                      value={feed.url}
                      onChange={(event) =>
                        updateFeed(feed.draftKey, (current) => ({
                          ...current,
                          url: event.target.value,
                        }))
                      }
                      placeholder="https://example.com/feed.xml"
                      validationStatus={validationStatus(feedValidation.url)}
                      errorMessage={feedValidation.url}
                      disabled={isSaving || isResetting}
                    />
                    <ValidatedInput
                      label="Refresh Minutes"
                      type="number"
                      min={1}
                      step={1}
                      value={String(feed.refreshMinutes)}
                      onChange={(event) =>
                        updateFeed(feed.draftKey, (current) => ({
                          ...current,
                          refreshMinutes:
                            Number.parseInt(event.target.value, 10) || 0,
                        }))
                      }
                      validationStatus={validationStatus(
                        feedValidation.refreshMinutes,
                      )}
                      errorMessage={feedValidation.refreshMinutes}
                      helperText="Per-feed minimum refresh interval."
                      disabled={isSaving || isResetting}
                    />
                  </div>

                  {duplicateIds.has(feed.id) ? (
                    <p className="mt-3 text-xs font-mono text-negative">
                      Feed IDs must stay unique. Rename one of the duplicate
                      custom feeds.
                    </p>
                  ) : null}
                </article>
              );
            })}
          </div>

          <div className="mt-5 flex flex-wrap justify-between gap-3">
            <button
              type="button"
              onClick={handleAddFeed}
              className="inline-flex items-center gap-2 rounded border border-[var(--term-status-info-border)] bg-[var(--term-status-info)] px-4 py-2 text-xs font-mono text-[var(--term-status-info-strong)] transition-colors hover:border-info hover:text-term-text"
              disabled={isSaving || isResetting}
            >
              <Plus className="h-3.5 w-3.5" />
              Add Feed
            </button>

            <div className="flex flex-wrap justify-end gap-3">
              {hasChanges ? (
                <button
                  type="button"
                  onClick={handleDiscardChanges}
                  className="rounded border border-term-border bg-term-highlight px-4 py-2 text-xs font-mono text-term-text-muted transition-colors hover:border-term-border-focus hover:text-term-text"
                  disabled={isSaving || isResetting}
                >
                  Discard Changes
                </button>
              ) : null}
              <button
                type="button"
                onClick={handleReset}
                className="inline-flex items-center gap-2 rounded border border-[var(--term-status-warning-border)] bg-[var(--term-status-warning)] px-4 py-2 text-xs font-mono text-warning transition-colors hover:brightness-110 disabled:opacity-50"
                disabled={isLoading || isSaving || isResetting}
              >
                {isResetting ? (
                  <>
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                    Resetting...
                  </>
                ) : (
                  <>
                    <RotateCcw className="h-3.5 w-3.5" />
                    Reset to Defaults
                  </>
                )}
              </button>
              <button
                type="button"
                onClick={handleSave}
                disabled={isLoading || isSaving || isResetting || !hasChanges}
                className="inline-flex items-center gap-2 rounded border border-info bg-[var(--term-status-info)] px-4 py-2 text-xs font-mono text-info transition-colors hover:brightness-110 disabled:opacity-50"
              >
                {isSaving ? (
                  <>
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                    Saving...
                  </>
                ) : (
                  <>
                    <Save className="h-3.5 w-3.5" />
                    Save Feeds
                  </>
                )}
              </button>
            </div>
          </div>
        </>
      )}

      {success ? (
        <div className="mt-4 flex items-center gap-3 rounded-lg border border-[var(--term-status-success-border)] bg-[var(--term-status-success)] px-4 py-3 text-sm font-mono text-positive">
          <CheckCircle className="h-5 w-5" />
          <div className="flex-1">{success}</div>
          <button
            type="button"
            onClick={() => setSuccess(null)}
            className="text-positive opacity-60 transition-opacity hover:opacity-100"
            aria-label="Dismiss success message"
          >
            <XCircle className="h-4 w-4" />
          </button>
        </div>
      ) : null}

      {error ? (
        <div className="mt-4 flex items-center gap-3 rounded-lg border border-[var(--term-status-error-border)] bg-[var(--term-status-error)] px-4 py-3 text-sm font-mono text-negative">
          <XCircle className="h-5 w-5" />
          <div className="flex-1">{error}</div>
          <button
            type="button"
            onClick={() => setError(null)}
            className="text-negative opacity-60 transition-opacity hover:opacity-100"
            aria-label="Dismiss error message"
          >
            <XCircle className="h-4 w-4" />
          </button>
        </div>
      ) : null}
    </section>
  );
};
