/**
 * Downloads Rules Tab
 *
 * Manage downloadable files that are accessible based on subscription conditions.
 * This system works alongside WooCommerce native downloadable products (not replacing them).
 *
 * @package ArraySubs
 */

import React, { useState, useEffect, useCallback } from "react";
import { __ } from "@wordpress/i18n";
import {
  Plus,
  Trash2,
  File,
  Upload,
  GripVertical,
  ChevronUp,
  ChevronDown,
} from "lucide-react";
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import {
  arrayMove,
  SortableContext,
  sortableKeyboardCoordinates,
  useSortable,
  verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { buildUrl } from "@libs/url";
import { ToastContainer } from "@libs/toast";
import { useToast } from "@libs/toast/useToast";
import { Skeleton } from "@libs/skeleton";
import RestrictionRuleBuilder, {
  defaultConditionTypes,
} from "@/components/RestrictionRuleBuilder";

/**
 * DownloadsRulesTab Component
 *
 * Manages downloadable file rules with conditions.
 * Files defined here appear on the customer's My Account downloads page
 * based on their subscription status.
 */

/**
 * SortableFileItem - Individual file with drag-and-drop
 */
const SortableFileItem = ({
  file,
  onUpdate,
  onRemove,
  onSelectFile,
  index,
  total,
}) => {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: file.id });

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
    zIndex: isDragging ? 1000 : 1,
  };

  return (
    <div
      ref={setNodeRef}
      style={style}
      className={`arraysubs-download-files__item ${
        isDragging ? "arraysubs-download-files__item--dragging" : ""
      }`}
    >
      <div
        className="arraysubs-download-files__item-drag"
        {...attributes}
        {...listeners}
      >
        <GripVertical size={16} />
      </div>
      <div className="arraysubs-download-files__item-fields">
        <input
          type="text"
          className="arraysubs-rule-field__input"
          value={file.name || ""}
          onChange={(e) => onUpdate(file.id, "name", e.target.value)}
          placeholder={__("Display name (shown to customer)", "arraysubs")}
        />
        <div className="arraysubs-download-files__file-row">
          <div className="arraysubs-download-files__file-info">
            {file.filename ? (
              <span className="arraysubs-download-files__filename">
                <File size={14} />
                {file.filename}
              </span>
            ) : (
              <span className="arraysubs-download-files__no-file">
                {__("No file selected", "arraysubs")}
              </span>
            )}
          </div>
        </div>
      </div>
      <div className="arraysubs-download-files__item-actions">
        <button
          type="button"
          className="arraysubs-download-files__item-action-btn"
          onClick={() => onUpdate(file.id, "_moveUp")}
          disabled={index === 0}
          title={__("Move up", "arraysubs")}
        >
          <ChevronUp size={16} />
        </button>
        <button
          type="button"
          className="arraysubs-download-files__item-action-btn"
          onClick={() => onUpdate(file.id, "_moveDown")}
          disabled={index === total - 1}
          title={__("Move down", "arraysubs")}
        >
          <ChevronDown size={16} />
        </button>
        <button
          type="button"
          className="arraysubs-download-files__item-action-btn"
          onClick={() => onSelectFile(file.id)}
          title={
            file.url
              ? __("Change File", "arraysubs")
              : __("Select File", "arraysubs")
          }
        >
          <Upload size={16} />
        </button>
        <button
          type="button"
          className="arraysubs-download-files__item-action-btn arraysubs-download-files__item-action-btn--delete"
          onClick={() => onRemove(file.id)}
          title={__("Remove file", "arraysubs")}
        >
          <Trash2 size={16} />
        </button>
      </div>
    </div>
  );
};

const DownloadsRulesTab = () => {
  const { env } = window.arraySubs;
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [rules, setRules] = useState([]);
  const { toasts, showToast, removeToast } = useToast();

  // Sensors for drag-and-drop (must be at component level)
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8,
      },
    }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  /**
   * Load settings on mount
   */
  useEffect(() => {
    loadData();
  }, []);

  /**
   * Fetch download rules
   */
  const loadData = async () => {
    setLoading(true);
    try {
      const response = await fetch(
        buildUrl(`${env?.apiBaseUrl}arraysubs/v1/members-access/settings`, {}),
        { headers: { "X-WP-Nonce": env?.nonce } },
      );

      if (!response.ok) {
        throw new Error(__("Failed to load data", "arraysubs"));
      }

      const data = await response.json();
      setRules(data.data?.download_rules || []);
    } catch (error) {
      console.error("Error loading download rules:", error);
      showToast(__("Failed to load download rules", "arraysubs"), "error");
    } finally {
      setLoading(false);
    }
  };

  /**
   * Save rules to server
   */
  const saveRules = async () => {
    setSaving(true);
    try {
      const response = await fetch(
        buildUrl(`${env?.apiBaseUrl}arraysubs/v1/members-access/settings`, {}),
        {
          method: "POST",
          headers: {
            "X-WP-Nonce": env?.nonce,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            download_rules: rules,
          }),
        },
      );

      if (!response.ok) {
        throw new Error(__("Failed to save rules", "arraysubs"));
      }

      showToast(__("Rules saved successfully!", "arraysubs"), "success");
    } catch (error) {
      console.error("Error saving rules:", error);
      showToast(__("Failed to save rules", "arraysubs"), "error");
    } finally {
      setSaving(false);
    }
  };

  /**
   * Get default rule structure for download rules
   */
  const getDefaultRule = useCallback(() => {
    return {
      enabled: true,
      name: __("New Download Rule", "arraysubs"),
      files: [],
      conditions: { logic: "and", rules: [] },
      schedule_enabled: false,
      schedule_value: 0,
      schedule_unit: "days",
    };
  }, []);

  /**
   * Add a file to rule
   */
  const addFile = (rule, updateRule) => {
    const files = rule.files || [];
    updateRule({
      files: [
        ...files,
        {
          id: Date.now(),
          name: "",
          url: "",
        },
      ],
    });
  };

  /**
   * Update a file in rule
   */
  const updateFile = (rule, updateRule, fileId, field, value) => {
    const files = rule.files || [];
    const fileIndex = files.findIndex((f) => f.id === fileId);

    if (fileIndex === -1) return;

    // Handle manual reorder
    if (field === "_moveUp" && fileIndex > 0) {
      const newFiles = [...files];
      [newFiles[fileIndex - 1], newFiles[fileIndex]] = [
        newFiles[fileIndex],
        newFiles[fileIndex - 1],
      ];
      updateRule({ files: newFiles });
      return;
    }

    if (field === "_moveDown" && fileIndex < files.length - 1) {
      const newFiles = [...files];
      [newFiles[fileIndex], newFiles[fileIndex + 1]] = [
        newFiles[fileIndex + 1],
        newFiles[fileIndex],
      ];
      updateRule({ files: newFiles });
      return;
    }

    // Regular field update
    const updatedFiles = files.map((file) =>
      file.id === fileId ? { ...file, [field]: value } : file,
    );
    updateRule({ files: updatedFiles });
  };

  /**
   * Handle drag end for files
   */
  const handleFileDragEnd = (rule, updateRule, event) => {
    const { active, over } = event;

    if (!over || active.id === over.id) return;

    const files = rule.files || [];
    const oldIndex = files.findIndex((f) => f.id === active.id);
    const newIndex = files.findIndex((f) => f.id === over.id);

    if (oldIndex !== -1 && newIndex !== -1) {
      updateRule({ files: arrayMove(files, oldIndex, newIndex) });
    }
  };

  /**
   * Remove a file from rule
   */
  const removeFile = (rule, updateRule, fileId) => {
    const files = (rule.files || []).filter((file) => file.id !== fileId);
    updateRule({ files });
  };

  /**
   * Open WordPress media library
   */
  const openMediaLibrary = (rule, updateRule, fileId) => {
    if (!window.wp || !window.wp.media) {
      showToast(__("Media library not available", "arraysubs"), "error");
      return;
    }

    const mediaFrame = window.wp.media({
      title: __("Select File", "arraysubs"),
      button: { text: __("Use this file", "arraysubs") },
      multiple: false,
    });

    mediaFrame.on("select", () => {
      const attachment = mediaFrame.state().get("selection").first().toJSON();
      const files = (rule.files || []).map((file) =>
        file.id === fileId
          ? {
              ...file,
              name: file.name || attachment.title || attachment.filename,
              url: attachment.url,
              filename: attachment.filename,
            }
          : file,
      );
      updateRule({ files });
    });

    mediaFrame.open();
  };

  /**
   * Render target fields for the TARGET section (files list)
   */
  const renderTargetFields = useCallback(
    (rule, updateRule) => {
      const files = rule.files || [];
      const fileIds = files.map((f) => f.id);

      return (
        <div className="arraysubs-download-files">
          <div className="arraysubs-download-files__header">
            <label className="arraysubs-rule-field__label">
              {__("Downloadable Files", "arraysubs")}
            </label>
            <button
              type="button"
              className="button button-secondary button-small"
              onClick={() => addFile(rule, updateRule)}
            >
              <Plus size={14} />
              {__("Add File", "arraysubs")}
            </button>
          </div>

          {files.length === 0 ? (
            <p className="arraysubs-download-files__empty">
              {__(
                "No files added. Add files that will be available to download when conditions are met.",
                "arraysubs",
              )}
            </p>
          ) : (
            <DndContext
              sensors={sensors}
              collisionDetection={closestCenter}
              onDragEnd={(event) => handleFileDragEnd(rule, updateRule, event)}
            >
              <SortableContext
                items={fileIds}
                strategy={verticalListSortingStrategy}
              >
                <div className="arraysubs-download-files__list">
                  {files.map((file, index) => (
                    <SortableFileItem
                      key={file.id}
                      file={file}
                      index={index}
                      total={files.length}
                      onUpdate={(fileId, field, value) =>
                        updateFile(rule, updateRule, fileId, field, value)
                      }
                      onRemove={(fileId) =>
                        removeFile(rule, updateRule, fileId)
                      }
                      onSelectFile={(fileId) =>
                        openMediaLibrary(rule, updateRule, fileId)
                      }
                    />
                  ))}
                </div>
              </SortableContext>
            </DndContext>
          )}

          <p className="arraysubs-rule-field__help">
            {__(
              "These files will appear on the customer's My Account → Downloads page when they meet the conditions below.",
              "arraysubs",
            )}
          </p>
        </div>
      );
    },
    [sensors, showToast],
  );

  /**
   * Render action fields for the THEN section (empty - conditions are enough)
   */
  const renderActionFields = useCallback(() => {
    return (
      <div className="arraysubs-download-action-info">
        <p>
          {__(
            "When a customer meets the conditions above, the files will be available for download in their My Account area.",
            "arraysubs",
          )}
        </p>
      </div>
    );
  }, []);

  /**
   * Render loading state
   */
  if (loading) {
    return (
      <div className="arraysubs-members-access__tab-content">
        <Skeleton count={3} height={100} />
      </div>
    );
  }

  return (
    <div className="arraysubs-members-access__tab-content">
      {/* Header with description */}
      <div className="arraysubs-members-access__section-header">
        <div className="arraysubs-members-access__section-info">
          <h3>{__("Download Rules", "arraysubs")}</h3>
          <p>
            {__(
              "Define downloadable files that become available to customers based on their subscription status. " +
                "This works alongside WooCommerce's native downloadable products.",
              "arraysubs",
            )}
          </p>
        </div>
      </div>

      <div className="arraysubs-members-access__info-box">
        <h4>{__("How Download Rules Work", "arraysubs")}</h4>
        <ol>
          <li>
            {__(
              "Define who qualifies using the IF conditions — for example, customers with an active subscription, customers assigned to a certain membership product, or users matching another rule condition.",
              "arraysubs",
            )}
          </li>
          <li>
            {__(
              "Choose what files to provide in the TARGET section. These files are attached to the rule and shown with the display names you choose.",
              "arraysubs",
            )}
          </li>
          <li>
            {__(
              "When a customer matches the rule, the files appear in My Account → Downloads. If they stop qualifying later, those rule-based files are no longer shown for future access.",
              "arraysubs",
            )}
          </li>
          <li>
            {__(
              "You can include multiple files per rule and reorder them to control how they appear to the customer.",
              "arraysubs",
            )}
          </li>
          <li>
            {__(
              "Use this for bonus resources, member guides, PDFs, templates, software files, or gated companion downloads that should not live directly on a WooCommerce product.",
              "arraysubs",
            )}
          </li>
        </ol>
        <p className="arraysubs-members-access__info-note">
          <strong>{__("Note:", "arraysubs")}</strong>{" "}
          {__(
            "WooCommerce downloadable products on the product edit screen continue to work normally. Download Rules add extra membership-based files alongside that native WooCommerce system rather than replacing it.",
            "arraysubs",
          )}
        </p>
      </div>

      {/* Rule Builder */}
      <RestrictionRuleBuilder
        rules={rules}
        onChange={setRules}
        ruleType="download"
        conditionTypes={defaultConditionTypes}
        renderTargetFields={renderTargetFields}
        renderActionFields={renderActionFields}
        getDefaultRule={getDefaultRule}
        ruleLabel={__("Download Rule", "arraysubs")}
        showSchedule
      />

      {/* Save Button */}
      <div className="arraysubs-members-access__actions arraysubs-bottom-fixed-actions">
        <div>
          <button
            type="button"
            className="button button-primary"
            onClick={saveRules}
            disabled={saving}
          >
            {saving
              ? __("Saving...", "arraysubs")
              : __("Save Settings", "arraysubs")}
          </button>
        </div>
      </div>

      <ToastContainer toasts={toasts} removeToast={removeToast} />
    </div>
  );
};

export default DownloadsRulesTab;
