/* eslint-disable @typescript-eslint/no-unused-vars */
import { ComponentsOverride, AttributesOverride, FlattenedKeyType, FlattenKeys } from '@/client/useHusar.js';
import { buildGraphQLBody, buildMeta, unflattenState } from '@/shared/payload';
import { TailwindPlay } from '@/TailwindPlay/TailwindRenderer.js';
import { ModelTypes } from '@/zeus/index.js';

export function HusarComponents<ZEUS, ZEUS_MODELS>(
  host?: readonly [string, { readonly headers?: { husar_token: string } | undefined }],
) {
  type Models = ZEUS extends { ModelEnum: infer R } ? keyof R : never;
  type Shapes = ZEUS extends { ShapeEnum: infer R } ? keyof R : never;
  type Views = ZEUS extends { ViewEnum: infer R } ? keyof R : never;
  // Map nested model type -> flat state map: key is flattened path, value is flattened value type
  type FlatState<T> = Partial<{ [K in FlattenKeys<T>]: FlattenedKeyType<T, Extract<K, string>> }>;
  type SubmitWithPrefix<SData> = (data: SData | undefined, prefix: string) => Promise<void>;

  // Local factory to unify onSubmit handling across View/Model/Shape
  function makeOnSubmit<SData extends Record<string, unknown>>({
    name,
    fields,
    entityType,
    submit,
  }: {
    name: string;
    fields: ModelTypes['CMSField'][];
    entityType: 'view' | 'model' | 'shape';
    submit?: (data: SData | undefined) => Promise<void>;
  }): SubmitWithPrefix<SData> {
    let onSubmit: SubmitWithPrefix<SData>;
    if (!submit) {
      onSubmit = async (data, prefix) => {
        if (!host) return;
        try {
          const unflattenedData = unflattenState<SData>(data as Record<string, unknown>);
          const meta = buildMeta({
            entityType,
            entityName: name,
            prefix,
          });
          const body = buildGraphQLBody({
            name,
            rootFields: fields,
            state: (unflattenedData as Record<string, unknown>) || {},
            meta,
          });
          const extra = host?.[1] || {};
          const headers = { 'Content-Type': 'application/json', ...(extra.headers || {}) };
          const response = await fetch(host[0], {
            ...extra,
            method: 'POST',
            headers,
            credentials: 'include',
            body,
          });
          const result = await response.json();
          const ok = !result.errors && !!result.data?.submitResponseState;
          if (!ok) {
            console.error('GraphQL submission error:', result.errors || result.data);
          }
        } catch (error) {
          console.error('Submission failed:', error);
        }
      };
    } else onSubmit = (data) => submit(data);
    return onSubmit;
  }

  function View<T extends Views = Views>({
    name,
    data,
    fields,
    components,
    attributes,
    state,
    setState,
    onSubmit: submit,
  }: {
    name: T;
    data?: (T extends string ? (`View${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`View${T}`] : never) : never) | null;
    fields: ModelTypes['CMSField'][];
    components?: ComponentsOverride<
      T extends string ? (`View${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`View${T}`] : never) : never
    >;
    attributes?: AttributesOverride<
      T extends string ? (`View${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`View${T}`] : never) : never
    >;
    state?: FlatState<
      T extends string ? (`View${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`View${T}`] : never) : never
    >;
    setState?: (
      state: FlatState<
        T extends string ? (`View${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`View${T}`] : never) : never
      >,
    ) => void;
    onSubmit?: (
      data:
        | FlatState<T extends string ? (`View${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`View${T}`] : never) : never>
        | undefined,
    ) => Promise<void>;
  }) {
    type ViewModel = T extends string
      ? `View${T}` extends keyof ZEUS_MODELS
        ? ZEUS_MODELS[`View${T}`]
        : never
      : never;
    type ViewState = FlatState<ViewModel>;
    const onSubmit = makeOnSubmit<ViewState>({ name: String(name), fields, entityType: 'view', submit });
    return (
      <TailwindPlay
        components={components as Parameters<typeof TailwindPlay>[0]['components']}
        fields={fields}
        modelData={data || undefined}
        attributes={attributes as Parameters<typeof TailwindPlay>[0]['attributes']}
        state={state as unknown as Record<string, unknown>}
        setState={setState ? (v) => setState(v as ViewState) : undefined}
        onSubmit={(v, prefix) => onSubmit(v as ViewState, prefix)}
      />
    );
  }
  function Model<T extends Models = Models>({
    name,
    data,
    fields,
    components,
    attributes,
    state,
    setState,
    onSubmit: submit,
  }: {
    name: T;
    data?: (T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never) | null;
    fields: ModelTypes['CMSField'][];
    components?: ComponentsOverride<T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never>;
    attributes?: AttributesOverride<T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never>;
    state?: FlatState<T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never>;
    setState?: (state: FlatState<T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never>) => void;
    onSubmit?: (data: FlatState<T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never> | undefined) => Promise<void>;
  }) {
    type ModelModel = T extends keyof ZEUS_MODELS ? ZEUS_MODELS[T] : never;
    type ModelState = FlatState<ModelModel>;
    const onSubmit = makeOnSubmit<ModelState>({ name: String(name), fields, entityType: 'model', submit });
    return (
      <TailwindPlay
        components={components as Parameters<typeof TailwindPlay>[0]['components']}
        fields={fields}
        modelData={data || undefined}
        attributes={attributes as Parameters<typeof TailwindPlay>[0]['attributes']}
        state={state as unknown as Record<string, unknown>}
        setState={setState ? (v) => setState(v as ModelState) : undefined}
        onSubmit={(v, prefix) => onSubmit(v as ModelState, prefix)}
      />
    );
  }
  function Shape<T extends Shapes = Shapes>({
    name,
    data,
    fields,
    components,
    attributes,
    state,
    setState,
    onSubmit: submit,
  }: {
    name: T;
    data?:
      | (T extends string ? (`Shape${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`Shape${T}`] : never) : never)
      | null;
    fields: ModelTypes['CMSField'][];
    components?: ComponentsOverride<
      T extends string ? (`Shape${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`Shape${T}`] : never) : never
    >;
    attributes?: AttributesOverride<
      T extends string ? (`Shape${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`Shape${T}`] : never) : never
    >;
    state?: FlatState<
      T extends string ? (`Shape${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`Shape${T}`] : never) : never
    >;
    setState?: (
      state: FlatState<
        T extends string ? (`Shape${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`Shape${T}`] : never) : never
      >,
    ) => void;
    onSubmit?: (
      data:
        | FlatState<
            T extends string ? (`Shape${T}` extends keyof ZEUS_MODELS ? ZEUS_MODELS[`Shape${T}`] : never) : never
          >
        | undefined,
    ) => Promise<void>;
  }) {
    type ShapeModel = T extends string
      ? `Shape${T}` extends keyof ZEUS_MODELS
        ? ZEUS_MODELS[`Shape${T}`]
        : never
      : never;
    type ShapeState = FlatState<ShapeModel>;
    const onSubmit = makeOnSubmit<ShapeState>({ name: String(name), fields, entityType: 'shape', submit });
    return (
      <TailwindPlay
        components={components as Parameters<typeof TailwindPlay>[0]['components']}
        fields={fields}
        modelData={data || undefined}
        attributes={attributes as Parameters<typeof TailwindPlay>[0]['attributes']}
        state={state as unknown as Record<string, unknown>}
        setState={setState ? (v) => setState(v as ShapeState) : undefined}
        onSubmit={(v, prefix) => onSubmit(v as ShapeState, prefix)}
      />
    );
  }

  return { View, Model, Shape };
}
