import React, { useEffect, useState, useCallback } from "react";
import { useNavigate, useParams } from "react-router-dom";
import {
  Box,
  Typography,
  Button,
  Paper,
  Grid,
  CircularProgress,
  Alert,
  Snackbar,
} from "@mui/material";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import SaveIcon from "@mui/icons-material/Save";
import type { ResourceConfig, FieldConfig } from "../types";
import { useResource } from "../context/useResource";
import { useAppContext } from "../context/AppContext";
import { getApi } from "../hooks/useApi";
import { FormFieldRenderer } from "./fields";
import { extractFields } from "../transformers/field-config";

interface ResourceFormProps {
  resource: ResourceConfig;
  basePath: string;
  mode: "create" | "edit";
}

export function ResourceForm({ resource, basePath, mode }: ResourceFormProps) {
  const navigate = useNavigate();
  const { id } = useParams();
  const crud = useResource(resource);
  const { resources: allResources } = useAppContext();
  const [formData, setFormData] = useState<Record<string, any>>({});
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [saving, setSaving] = useState(false);
  const [snackbar, setSnackbar] = useState<{ open: boolean; message: string; severity: "success" | "error" }>({
    open: false,
    message: "",
    severity: "success",
  });

  const [fkOptions, setFkOptions] = useState<Record<string, { value: any; label: string }[]>>({});
  const [fkLoading, setFkLoading] = useState<Record<string, boolean>>({});
  const { schemas } = useAppContext();

  useEffect(() => {
    console.log(`[ResourceForm] mounted resource="${resource.name}" mode=${mode} id=${id}`);
    console.log(`[ResourceForm] relationships:`, resource.relationships.map(r => `{field=${r.fieldName} target=${r.config.resource} prefetch=${r.config.prefetch}}`));
  }, []);

  useEffect(() => {
    if (mode === "create") {
      const initial: Record<string, any> = {};
      resource.orderedFields.forEach((f) => {
        if (f.refSchema && !f.fk && formData[f.name] === undefined) {
          const refSchemaObj = schemas[f.refSchema!];
          if (refSchemaObj) {
            const nestedFields = extractFields(f.refSchema!, refSchemaObj, schemas);
            initial[f.name] = f.isArray ? [] : buildInitialShape(nestedFields, schemas);
          } else {
            initial[f.name] = null;
          }
        }
      });
      if (Object.keys(initial).length > 0) {
        setFormData((prev) => ({ ...prev, ...initial }));
      }
    }
  }, [mode, resource.name]);

  const loadFkOptions = useCallback(async (fieldName: string, fk: { resource: string; prefetch: boolean }) => {
    console.log(`[loadFkOptions] CALLED field="${fieldName}" resource="${fk.resource}" prefetch=${fk.prefetch}`);
    setFkLoading((prev) => ({ ...prev, [fieldName]: true }));
    try {
      const targetRes = allResources.find((r) => r.name === fk.resource);
      if (!targetRes) {
        console.log(`[loadFkOptions] targetRes NOT FOUND for "${fk.resource}"`);
        return;
      }
      console.log(`[loadFkOptions] targetRes found: path="${targetRes.path}" pagination=${!!targetRes.pagination}`);

      const api = getApi();
      const params: Record<string, any> = {};
      if (targetRes.pagination) {
        params.limit = 0;
      }
      console.log(`[loadFkOptions] fetching GET ${targetRes.path}`, params);
      const res = await api.get(targetRes.path, { params });
      console.log(`[loadFkOptions] response status=${res.status} data type=${typeof res.data} isArray=${Array.isArray(res.data)}`);

      let items: any[];
      if (targetRes.pagination) {
        if (!res.data || typeof res.data !== "object" || !Array.isArray(res.data.items)) {
          console.log(`[loadFkOptions] paginated parse FAILED: data=`, res.data);
          throw new Error(`Expected paginated response from ${targetRes.path}`);
        }
        items = res.data.items;
        console.log(`[loadFkOptions] paginated: total=${res.data.total} items.length=${items.length}`);
      } else {
        if (!Array.isArray(res.data)) {
          console.log(`[loadFkOptions] non-paginated parse FAILED: data=`, res.data);
          throw new Error(`Expected array response from ${targetRes.path}`);
        }
        items = res.data;
        console.log(`[loadFkOptions] non-paginated: items.length=${items.length}`);
      }

      const opts = items.map((item: any) => ({
        value: item[targetRes.primaryKey],
        label: applyFormat(item, targetRes.displayFormat),
      }));
      console.log(`[loadFkOptions] computed ${opts.length} options for field "${fieldName}"`, opts.slice(0, 3));

      setFkOptions((prev) => ({ ...prev, [fieldName]: opts }));
    } catch (e) {
      console.log(`[loadFkOptions] ERROR field="${fieldName}":`, e);
    } finally {
      setFkLoading((prev) => ({ ...prev, [fieldName]: false }));
    }
  }, [allResources]);

  useEffect(() => {
    console.log(`[prefetch effect] ${resource.relationships.length} relationships, checking prefetch...`);
    resource.relationships.forEach((rel) => {
      console.log(`[prefetch effect] field="${rel.fieldName}" prefetch=${rel.config.prefetch} -> ${rel.config.prefetch ? "WILL FETCH" : "skipped (onFocus)"}`);
      if (rel.config.prefetch) {
        loadFkOptions(rel.fieldName, rel.config);
      }
    });
  }, [resource.relationships, loadFkOptions]);

  useEffect(() => {
    if (mode === "edit" && id) {
      crud.get(id).then((data) => {
        const resolved = { ...(data ?? {}) };
        resource.relationships.forEach((rel) => {
          const val = resolved[rel.fieldName];
          if (val != null) {
            const targetRes = allResources.find((r) => r.name === rel.config.resource);
            if (targetRes) {
              if (Array.isArray(val)) {
                resolved[rel.fieldName] = val.map((item: any) => item[targetRes.primaryKey]);
              } else if (typeof val === "object") {
                resolved[rel.fieldName] = val[targetRes.primaryKey];
              }
            }
            if (!rel.config.prefetch) {
              loadFkOptions(rel.fieldName, rel.config);
            }
          }
        });
        setFormData(resolved);
      });
    }
  }, [mode, id, loadFkOptions, resource.relationships]);

  const loadFkOnFocus = (fieldName: string) => {
    console.log(`[loadFkOnFocus] CALLED field="${fieldName}"`);
    const rel = resource.relationships.find((r) => r.fieldName === fieldName);
    if (rel) {
      console.log(`[loadFkOnFocus] found rel: prefetch=${rel.config.prefetch} fkOptions[${fieldName}]=${fkOptions[fieldName] ? "exists" : "undefined"}`);
    } else {
      console.log(`[loadFkOnFocus] NO RELATIONSHIP found for field="${fieldName}"`);
    }
    if (rel && !rel.config.prefetch && !fkOptions[fieldName]) {
      console.log(`[loadFkOnFocus] conditions met -> calling loadFkOptions`);
      loadFkOptions(fieldName, rel.config);
    } else {
      console.log(`[loadFkOnFocus] NOT calling loadFkOptions: rel=${!!rel} !prefetch=${rel && !rel.config.prefetch} !hasOptions=${!fkOptions[fieldName]}`);
    }
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const validationErrors: Record<string, string> = {};
    resource.orderedFields
      .filter((f) => f.required && !f.readOnly && f.name !== resource.primaryKey)
      .forEach((f) => {
        if (formData[f.name] === undefined || formData[f.name] === null || formData[f.name] === "") {
          validationErrors[f.name] = `${f.label} is required`;
        }
      });

    if (Object.keys(validationErrors).length > 0) {
      setErrors(validationErrors);
      return;
    }

    setErrors({});
    setSaving(true);

    try {
      if (mode === "create") {
        await crud.create(formData);
        setSnackbar({ open: true, message: "Created successfully", severity: "success" });
        navigate(`${basePath}/${resource.name}`);
      } else {
        await crud.update(id!, formData);
        setSnackbar({ open: true, message: "Updated successfully", severity: "success" });
        navigate(`${basePath}/${resource.name}/${id}`);
      }
    } catch (e: any) {
      setSnackbar({ open: true, message: e.message ?? "Operation failed", severity: "error" });
    } finally {
      setSaving(false);
    }
  };

  const handleChange = (fieldName: string, value: any) => {
    setFormData((prev) => ({ ...prev, [fieldName]: value }));
    if (errors[fieldName]) {
      setErrors((prev) => {
        const copy = { ...prev };
        delete copy[fieldName];
        return copy;
      });
    }
  };

  const title = mode === "create" ? `Create ${resource.schemaName}` : `Edit ${resource.schemaName}`;

  return (
    <Box>
      <Box sx={{ display: "flex", alignItems: "center", gap: 1, mb: 3 }}>
        <Button startIcon={<ArrowBackIcon />} onClick={() => navigate(`${basePath}/${resource.name}`)}>
          Back
        </Button>
        <Typography variant="h5" fontWeight={700}>
          {title}
        </Typography>
      </Box>

      <Paper variant="outlined" sx={{ p: 3 }}>
        <Box component="form" onSubmit={handleSubmit}>
          <Grid container spacing={2}>
            {resource.orderedFields
              .filter((f) => !(f.name === resource.primaryKey && mode === "edit"))
              .map((field) => (
                <Grid item xs={12} sm={6} md={4} key={field.name}>
                  <FormFieldRenderer
                    field={field}
                    value={formData[field.name]}
                    onChange={(val) => handleChange(field.name, val)}
                    error={errors[field.name]}
                    fkOptions={fkOptions[field.name]}
                    fkLoading={fkLoading[field.name]}
                    recordId={id}
                    onFkOpen={loadFkOnFocus}
                  />
                </Grid>
              ))}
          </Grid>

          <Box sx={{ mt: 3, display: "flex", gap: 2 }}>
            <Button
              type="submit"
              variant="contained"
              startIcon={saving ? <CircularProgress size={18} color="inherit" /> : <SaveIcon />}
              disabled={saving}
            >
              {mode === "create" ? "Create" : "Save Changes"}
            </Button>
            <Button variant="outlined" onClick={() => navigate(`${basePath}/${resource.name}`)}>
              Cancel
            </Button>
          </Box>
        </Box>
      </Paper>

      <Snackbar
        open={snackbar.open}
        autoHideDuration={4000}
        onClose={() => setSnackbar((s) => ({ ...s, open: false }))}
      >
        <Alert severity={snackbar.severity} onClose={() => setSnackbar((s) => ({ ...s, open: false }))}>
          {snackbar.message}
        </Alert>
      </Snackbar>
    </Box>
  );
}

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

function buildInitialShape(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 ? [] : buildInitialShape(nestedFields, schemas);
    } else {
      shape[f.name] = null;
    }
  }
  return shape;
}
