import React, { createContext, useContext, useState, useEffect } from "react";
import {
  developerKitService,
} from "@/services/developerKit.service";
import { ApiEndpoint, ApiMigration, CreateUpdateCustomEntityDto, CustomEntity } from "@/proxy/developerKit/models";

export const FIELD_TYPE_OPTIONS = [
  { label: "String", value: "string" },
  { label: "Number", value: "number" },
  { label: "Boolean", value: "boolean" },
  { label: "Date", value: "date" },
  { label: "Guid", value: "guid" },
  { label: "Decimal", value: "decimal" },
] as const;

export type EntityFieldType = (typeof FIELD_TYPE_OPTIONS)[number]["value"];

interface EntityContextType {
  entities: CustomEntity[];
  migrations: ApiMigration[];
  generatedEndpoints: ApiEndpoint[];
  loading: boolean;
  error: string | null;
  // Entity operations
  addEntity: (entity: CreateUpdateCustomEntityDto) => Promise<void>;
  updateEntity: (id: string, entity: CreateUpdateCustomEntityDto) => Promise<void>;
  deleteEntity: (id: string) => Promise<void>;
  getEntity: (id: string) => CustomEntity | undefined;
  refreshEntities: () => Promise<void>;
  toggleEntityActiveStatus: (id: string) => Promise<void>;
  // Migration operations
  generateMigration: (entityId: string) => Promise<void>;
  applyMigration: (migrationId: string) => Promise<void>;
  getEntityMigrations: (entityId: string) => ApiMigration[];
  deleteMigration: (id: string) => Promise<void>;
  // Generated endpoint operations
  generateCrudEndpoints: (entityId: string) => Promise<void>;
  toggleEndpoint: (endpointId: string) => Promise<void>;
  getEntityEndpoints: (entityId: string) => ApiEndpoint[];
  deleteGeneratedEndpoint: (id: string) => Promise<void>;
}

const EntityContext = createContext<EntityContextType | undefined>(undefined);

// eslint-disable-next-line react-refresh/only-export-components
export const useEntities = () => {
  const context = useContext(EntityContext);
  if (context === undefined) {
    throw new Error("useEntities must be used within an EntityProvider");
  }
  return context;
};

export const EntityProvider: React.FC<{ children: React.ReactNode }> = ({
  children,
}) => {
  const [entities, setEntities] = useState<CustomEntity[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const [migrations, setMigrations] = useState<ApiMigration[]>([]);
  const [generatedEndpoints, setGeneratedEndpoints] = useState<ApiEndpoint[]>([]);

  const refreshEntities = async () => {
    try {
      setLoading(true);
      setError(null);
      const [entitiesData, migrationsData, generatedEndpointsData] =
        await Promise.all([
          developerKitService.getCustomEntities(),
          developerKitService.getMigrations(),
          developerKitService.getGeneratedEndpoints(),
        ]);
      setEntities(entitiesData.items || []);
      setMigrations(migrationsData.items || []);
      setGeneratedEndpoints(generatedEndpointsData.items || []);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to fetch data");
      console.error("Failed to fetch data:", err);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    refreshEntities();
  }, []);

  const addEntity = async (entityData: CreateUpdateCustomEntityDto) => {
    try {
      setLoading(true);
      setError(null);
      const newEntity = await developerKitService.createCustomEntity(entityData);
      setEntities((prev) => [...prev, newEntity]);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to create entity");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const updateEntity = async (
    id: string,
    entityData: CreateUpdateCustomEntityDto
  ) => {
    try {
      setLoading(true);
      setError(null);
      const updatedEntity = await developerKitService.updateCustomEntity(id, entityData);
      setEntities((prev) =>
        prev.map((entity) => (entity.id === id ? updatedEntity : entity))
      );
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to update entity");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const deleteEntity = async (id: string) => {
    try {
      setLoading(true);
      setError(null);
      await developerKitService.deleteCustomEntity(id);
      
      // Remove entity from state
      setEntities((prev) => prev.filter((entity) => entity.id !== id));
      
      // Remove related migrations from state
      setMigrations((prev) => prev.filter((migration) => migration.entityId !== id));
      
      // Remove related endpoints from state
      setGeneratedEndpoints((prev) => prev.filter((endpoint) => endpoint.entityId !== id));
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to delete entity");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const toggleEntityActiveStatus = async (id: string) => {
    try {
      setLoading(true);
      setError(null);
      await developerKitService.toggleCustomEntityActiveStatus(id);
      // Refresh entities to get updated status
      await refreshEntities();
    } catch (err) {
      setError(
        err instanceof Error ? err.message : "Failed to toggle entity status"
      );
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const getEntity = (id: string): CustomEntity | undefined => {
    return entities.find((entity) => entity.id === id);
  };

  // Migration operations
  const generateMigration = async (entityId: string) => {
    try {
      setLoading(true);
      setError(null);
      const migration = await developerKitService.generateMigration(entityId);
      setMigrations((prev) => [...prev, migration]);
      // Refresh entities to get updated migration status
      await refreshEntities();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to generate migration");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const applyMigration = async (migrationId: string) => {
    try {
      setLoading(true);
      setError(null);
      const appliedMigration = await developerKitService.applyMigration(migrationId);
      setMigrations((prev) =>
        prev.map((m) => (m.id === migrationId ? appliedMigration : m))
      );
      // Refresh entities to get updated migration status
      await refreshEntities();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to apply migration");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const getEntityMigrations = (entityId: string): ApiMigration[] => {
    return migrations.filter((migration) => migration.entityId === entityId);
  };

  const deleteMigration = async (id: string) => {
    try {
      setLoading(true);
      setError(null);
      await developerKitService.deleteMigration(id);
      setMigrations((prev) => prev.filter((migration) => migration.id !== id));
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to delete migration");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  // Generated endpoint operations
  const generateCrudEndpoints = async (entityId: string) => {
    try {
      setLoading(true);
      setError(null);
      const endpointsData = await developerKitService.generateCrudEndpoints(entityId);
      // Replace existing endpoints for this entity
      setGeneratedEndpoints((prev) => [
        ...prev.filter((e) => e.entityId !== entityId),
        ...endpointsData.items || [],
      ]);
      // Refresh entities to get updated endpoint status
      await refreshEntities();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to generate CRUD endpoints");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const toggleEndpoint = async (endpointId: string) => {
    try {
      setLoading(true);
      setError(null);
      const updatedEndpoint = await developerKitService.toggleGeneratedEndpoint(endpointId);
      setGeneratedEndpoints((prev) =>
        prev.map((e) => (e.id === endpointId ? updatedEndpoint : e))
      );
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to toggle endpoint");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  const getEntityEndpoints = (entityId: string): ApiEndpoint[] => {
    return generatedEndpoints.filter((endpoint) => endpoint.entityId === entityId);
  };

  const deleteGeneratedEndpoint = async (id: string) => {
    try {
      setLoading(true);
      setError(null);
      await developerKitService.deleteGeneratedEndpoint(id);
      setGeneratedEndpoints((prev) => prev.filter((endpoint) => endpoint.id !== id));
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to delete generated endpoint");
      throw err;
    } finally {
      setLoading(false);
    }
  };

  return (
    <EntityContext.Provider
      value={{
        entities,
        migrations,
        generatedEndpoints,
        loading,
        error,
        addEntity,
        updateEntity,
        deleteEntity,
        getEntity,
        refreshEntities,
        toggleEntityActiveStatus,
        generateMigration,
        applyMigration,
        getEntityMigrations,
        deleteMigration,
        generateCrudEndpoints,
        toggleEndpoint,
        getEntityEndpoints,
        deleteGeneratedEndpoint,
      }}
    >
      {children}
    </EntityContext.Provider>
  );
};
