import React, { useState } from "react";
import {
  Button,
  Chip,
  Box,
  Typography,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  IconButton,
  Divider,
} from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import DeleteIcon from "@mui/icons-material/Delete";
import type { FieldConfig } from "../../../types";
import { useAppContext } from "../../../context/AppContext";
import { extractFields } from "../../../transformers/field-config";
import { FormFieldRenderer } from "../FormFieldRenderer";

interface JsonFieldProps {
  field: FieldConfig;
  value: any;
  onChange: (val: any) => void;
}

export function JsonField({ field, value, onChange }: JsonFieldProps) {
  const { schemas } = useAppContext();
  const [open, setOpen] = useState(false);

  const refSchema = field.refSchema ? schemas[field.refSchema] : null;
  const subFields = refSchema
    ? extractFields(field.refSchema!, refSchema, schemas)
    : [];

  const [editValue, setEditValue] = useState<any>(null);

  const handleOpen = () => {
    setEditValue(initEditValue(value, field, schemas));
    setOpen(true);
  };

  const handleSave = () => {
    onChange(editValue);
    setOpen(false);
  };

  const handleCancel = () => {
    setEditValue(null);
    setOpen(false);
  };

  const handleClear = () => {
    onChange(null);
    setOpen(false);
  };

  const handleAddItem = () => {
    setEditValue((prev: any[]) => [...(prev || []), buildDefaultShape(subFields, schemas)]);
  };

  const handleRemoveItem = (index: number) => {
    setEditValue((prev: any[]) => prev.filter((_: any, i: number) => i !== index));
  };

  const handleItemFieldChange = (index: number, fieldName: string, val: any) => {
    setEditValue((prev: any[]) => {
      const next = [...prev];
      next[index] = { ...next[index], [fieldName]: val };
      return next;
    });
  };

  const handleFieldChange = (fieldName: string, val: any) => {
    setEditValue((prev: any) => ({ ...prev, [fieldName]: val }));
  };

  if (!open) {
    if (value === null || value === undefined) {
      return (
        <Button variant="outlined" onClick={handleOpen} size="small">
          Set {field.label}
        </Button>
      );
    }

    if (field.isArray && Array.isArray(value)) {
      if (value.length === 0) {
        return (
          <Button variant="outlined" onClick={handleOpen} size="small">
            Set {field.label}
          </Button>
        );
      }
      return (
        <Chip
          label={`${value.length} item${value.length !== 1 ? "s" : ""}`}
          size="small"
          color="primary"
          variant="outlined"
          onClick={handleOpen}
          onDelete={handleClear}
        />
      );
    }

    if (typeof value === "object") {
      const summary = field.inlineDisplayFormat
        ? applyInlineFormat(value, field.inlineDisplayFormat)
        : Object.entries(value)
            .filter(([, v]) => v != null)
            .map(([k, v]) => `${k}: ${String(v)}`)
            .join(" | ");
      return (
        <Chip
          label={summary || field.label}
          size="small"
          color="primary"
          variant="outlined"
          onClick={handleOpen}
          onDelete={handleClear}
        />
      );
    }
  }

  return (
    <Dialog fullScreen open={open} onClose={handleCancel}>
      <DialogTitle>{field.label}</DialogTitle>
      <DialogContent dividers>
        {field.isArray ? (
          <ArrayEditor
            items={editValue ?? []}
            subFields={subFields}
            onAddItem={handleAddItem}
            onRemoveItem={handleRemoveItem}
            onFieldChange={handleItemFieldChange}
            schemas={schemas}
          />
        ) : (
          <ObjectEditor
            value={editValue}
            subFields={subFields}
            onFieldChange={handleFieldChange}
            schemas={schemas}
          />
        )}
      </DialogContent>
      <DialogActions>
        <Button onClick={handleClear} color="error">
          Clear
        </Button>
        <Button onClick={handleCancel}>Cancel</Button>
        <Button onClick={handleSave} variant="contained">
          Save
        </Button>
      </DialogActions>
    </Dialog>
  );
}

function ObjectEditor({
  value,
  subFields,
  onFieldChange,
}: {
  value: any;
  subFields: FieldConfig[];
  onFieldChange: (name: string, val: any) => void;
  schemas: Record<string, any>;
}) {
  return (
    <Box>
      {subFields.map((subField) => (
        <Box key={subField.name} sx={{ mb: 2 }}>
          <FormFieldRenderer
            field={subField}
            value={value?.[subField.name]}
            onChange={(val) => onFieldChange(subField.name, val)}
          />
        </Box>
      ))}
    </Box>
  );
}

function ArrayEditor({
  items,
  subFields,
  onAddItem,
  onRemoveItem,
  onFieldChange,
  schemas,
}: {
  items: any[];
  subFields: FieldConfig[];
  onAddItem: () => void;
  onRemoveItem: (index: number) => void;
  onFieldChange: (index: number, name: string, val: any) => void;
  schemas: Record<string, any>;
}) {
  return (
    <Box>
      {items.length === 0 && (
        <Typography variant="body2" color="text.disabled" sx={{ mb: 2 }}>
          No items added yet.
        </Typography>
      )}
      {items.map((item, index) => (
        <Box key={index} sx={{ mb: 2 }}>
          <Box sx={{ display: "flex", alignItems: "center", gap: 1, mb: 1 }}>
            <Typography variant="subtitle2" sx={{ flex: 1 }}>
              Item {index + 1}
            </Typography>
            <IconButton size="small" color="error" onClick={() => onRemoveItem(index)}>
              <DeleteIcon fontSize="small" />
            </IconButton>
          </Box>
          <Box sx={{ pl: 2 }}>
            {subFields.map((subField) => (
              <Box key={subField.name} sx={{ mb: 2 }}>
                <FormFieldRenderer
                  field={subField}
                  value={item?.[subField.name]}
                  onChange={(val) => onFieldChange(index, subField.name, val)}
                />
              </Box>
            ))}
          </Box>
          <Divider sx={{ mt: 2 }} />
        </Box>
      ))}
      <Button startIcon={<AddIcon />} onClick={onAddItem} variant="outlined" size="small">
        Add Item
      </Button>
    </Box>
  );
}

function buildDefaultShape(fields: FieldConfig[], schemas: Record<string, any>): Record<string, any> {
  const shape: Record<string, any> = {};
  for (const f of fields) {
    if (f.refSchema && !f.fk) {
      const refSchemaObj = schemas[f.refSchema!];
      const nestedFields = refSchemaObj ? extractFields(f.refSchema!, refSchemaObj, schemas) : [];
      shape[f.name] = f.isArray ? [] : buildDefaultShape(nestedFields, schemas);
    } else {
      shape[f.name] = null;
    }
  }
  return shape;
}

function initEditValue(value: any, field: FieldConfig, schemas: Record<string, any>): any {
  if (field.isArray) {
    return value ? value.map((item: any) => ({ ...item })) : [];
  }
  if (value && typeof value === "object") {
    return { ...value };
  }
  return buildDefaultShape(
    field.refSchema ? extractFields(field.refSchema, schemas[field.refSchema], schemas) : [],
    schemas
  );
}

function applyInlineFormat(obj: any, format: string): string {
  if (!obj || typeof obj !== "object") return String(obj ?? "");
  return format.replace(/\{(\w+)\}/g, (_, key) => String(obj[key] ?? ""));
}
