<template>
  <div :class="wrapperClass">
    <section v-if="!isRoot" class="rounded-lg border border-base-200 bg-base-100 p-4 space-y-3">
      <div class="space-y-1">
        <h4 class="text-sm font-semibold text-base-content">
          {{ requirementLabel }}
        </h4>
        <p class="text-xs text-base-content/70">
          {{ requirementDescription }}
        </p>
      </div>

      <div class="form-control">
        <label class="label">
          <span class="label-text text-xs">Sélectionner un composant</span>
        </label>
        <SearchSelect
          :model-value="assignment.selectedComponentId || ''"
          :options="componentOptions"
          :loading="componentsLoading"
          size="sm"
          placeholder="Rechercher un composant..."
          :empty-text="componentOptions.length ? 'Aucun résultat' : 'Aucun composant disponible'"
          :option-label="componentOptionLabel"
          :option-description="componentOptionDescription"
          @update:modelValue="(value) => { assignment.selectedComponentId = normalizeSelectionValue(value); }"
        />
      </div>
    </section>

    <section v-if="assignment.pieces.length" class="rounded-lg border border-dashed border-base-300 bg-base-200/40 p-4 space-y-4">
      <header class="space-y-1">
        <h4 class="text-sm font-semibold text-base-content">
          {{ isRoot ? 'Pièces requises par le squelette' : 'Pièces associées à ce sous-composant' }}
        </h4>
        <p class="text-xs text-base-content/70">
          Sélectionnez les pièces concrètes à associer pour chaque emplacement.
        </p>
      </header>

      <div
        v-for="pieceAssignment in assignment.pieces"
        :key="pieceAssignment.path"
        class="rounded-md border border-base-200 bg-base-100 p-3 space-y-2"
      >
        <div class="space-y-1">
          <p class="text-xs font-medium text-base-content">
            {{ describePieceRequirement(pieceAssignment.definition) }}
          </p>
          <p v-if="!getPieceOptions(pieceAssignment.definition).length" class="text-[11px] text-error">
            Aucune pièce disponible pour cette famille.
          </p>
        </div>

        <SearchSelect
          :model-value="pieceAssignment.selectedPieceId || ''"
          :options="getPieceOptions(pieceAssignment.definition)"
          :loading="piecesLoading"
          size="xs"
          placeholder="Rechercher une pièce..."
          :empty-text="getPieceOptions(pieceAssignment.definition).length ? 'Aucun résultat' : 'Aucune pièce disponible'"
          :option-label="pieceOptionLabel"
          :option-description="pieceOptionDescription"
          @update:modelValue="(value) => { pieceAssignment.selectedPieceId = normalizeSelectionValue(value); }"
        />
      </div>
    </section>

    <section v-if="assignment.subcomponents.length" class="space-y-4">
      <header class="space-y-1">
        <h4 class="text-sm font-semibold text-base-content">
          {{ isRoot ? 'Sous-composants définis par le squelette' : 'Sous-composants imbriqués' }}
        </h4>
        <p class="text-xs text-base-content/70">
          Choisissez un composant existant pour chaque sous-niveau requis.
        </p>
      </header>

      <ComponentStructureAssignmentNode
        v-for="subAssignment in assignment.subcomponents"
        :key="subAssignment.path"
        :assignment="subAssignment"
        :pieces="pieces"
        :components="components"
        :components-loading="componentsLoading"
        :pieces-loading="piecesLoading"
        :depth="depth + 1"
      />
    </section>
  </div>
</template>

<script setup lang="ts">
import { computed, watch } from 'vue';
import SearchSelect from '~/components/common/SearchSelect.vue';
import type {
  ComponentModelPiece,
  ComponentModelStructureNode,
} from '~/shared/types/inventory';

interface ComponentOption {
  id: string;
  name?: string | null;
  reference?: string | null;
  typeComposantId?: string | null;
  typeComposant?: {
    id: string;
    name?: string | null;
    code?: string | null;
  } | null;
}

interface PieceOption {
  id: string;
  name?: string | null;
  reference?: string | null;
  typePieceId?: string | null;
  typePiece?: {
    id: string;
    name?: string | null;
    code?: string | null;
  } | null;
}

export interface StructurePieceAssignment {
  path: string;
  definition: ComponentModelPiece;
  selectedPieceId: string;
}

export interface StructureAssignmentNode {
  path: string;
  definition: ComponentModelStructureNode;
  selectedComponentId: string;
  pieces: StructurePieceAssignment[];
  subcomponents: StructureAssignmentNode[];
}

const props = withDefaults(
  defineProps<{
    assignment: StructureAssignmentNode;
    pieces: PieceOption[] | null;
    components: ComponentOption[] | null;
    depth?: number;
    componentsLoading?: boolean;
    piecesLoading?: boolean;
  }>(),
  {
    depth: 0,
    pieces: () => [],
    components: () => [],
    componentsLoading: false,
    piecesLoading: false,
  },
);

const depth = computed(() => props.depth ?? 0);
const isRoot = computed(() => depth.value === 0);

const wrapperClass = computed(() =>
  depth.value === 0 ? 'space-y-6' : 'space-y-6 border-l border-base-300 pl-4',
);

const componentOptions = computed(() => {
  if (isRoot.value) {
    return [];
  }
  const definition = props.assignment.definition || {};
  const requiredTypeId =
    definition.typeComposantId || definition.modelId || null;
  const requiredFamilyCode = definition.familyCode || null;

  return (props.components || []).filter((component) => {
    if (!component || typeof component !== 'object') {
      return false;
    }
    if (requiredTypeId) {
      return component.typeComposantId === requiredTypeId;
    }
    if (requiredFamilyCode) {
      return (
        component.typeComposant?.code === requiredFamilyCode ||
        component.typeComposantId === requiredFamilyCode
      );
    }
    return true;
  });
});

const componentOptionLabel = (component?: ComponentOption | null) => {
  if (!component) {
    return 'Composant sans nom';
  }
  return component.name || 'Composant sans nom';
};

const componentOptionDescription = (component?: ComponentOption | null) => {
  if (!component) {
    return '';
  }
  const parts: string[] = [];
  const typeLabel =
    component.typeComposant?.name || component.typeComposant?.code || null;
  if (typeLabel) {
    parts.push(typeLabel);
  }
  if (component.reference) {
    parts.push(`Ref. ${component.reference}`);
  }
  return parts.join(' • ');
};

watch(
  componentOptions,
  (options) => {
    if (isRoot.value) {
      return;
    }
    const hasMatch = options.some(
      (component) => component.id === props.assignment.selectedComponentId,
    );
    if (!hasMatch) {
      props.assignment.selectedComponentId = '';
    }
  },
  { immediate: true },
);

const describePieceRequirement = (definition: ComponentModelPiece) => {
  const parts: string[] = [];
  const addPart = (value?: string | null) => {
    const trimmed = typeof value === 'string' ? value.trim() : '';
    if (trimmed && !parts.includes(trimmed)) {
      parts.push(trimmed);
    }
  };

  const options = getPieceOptions(definition);
  const fallbackPiece = options[0] || null;
  const fallbackType = fallbackPiece?.typePiece || null;

  addPart(definition.role);
  addPart(
    definition.typePieceLabel ||
      (definition as any).typePiece?.name ||
      fallbackType?.name,
  );

  const family =
    definition.familyCode ||
    (definition as any).typePiece?.code ||
    fallbackType?.code ||
    null;
  if (family) {
    addPart(`Famille ${family}`);
  }

  if (parts.length === 0) {
    addPart(fallbackType?.name);
    if (fallbackType?.code) {
      addPart(`Famille ${fallbackType.code}`);
    }
  }

  if (parts.length === 0 && definition.typePieceId) {
    addPart(`#${definition.typePieceId}`);
  }

  return parts.length ? parts.join(' • ') : 'Pièce du squelette';
};

const requirementLabel = computed(() => {
  const definition = props.assignment.definition || {};
  const alias = definition.alias || definition.typeComposantLabel;
  if (alias) {
    return alias;
  }
  if (definition.typeComposant?.name) {
    return definition.typeComposant.name;
  }
  if (definition.familyCode) {
    return `Famille ${definition.familyCode}`;
  }
  return 'Sous-composant';
});

const requirementDescription = computed(() => {
  const definition = props.assignment.definition || {};
  const family =
    definition.typeComposantLabel ||
    definition.typeComposant?.name ||
    definition.familyCode;
  if (family) {
    return `Doit appartenir à la famille "${family}".`;
  }
  return 'Sélectionnez un composant enfant conforme à cette position.';
});

const getPieceOptions = (definition: ComponentModelPiece) => {
  const requiredTypeId =
    definition.typePieceId ||
    (definition as any).typePiece?.id ||
    definition.familyCode ||
    null;

  return (props.pieces || []).filter((piece) => {
    if (!piece || typeof piece !== 'object') {
      return false;
    }
    if (!requiredTypeId) {
      return true;
    }
    if (definition.typePieceId || (definition as any).typePiece?.id) {
      return (
        piece.typePieceId === requiredTypeId ||
        piece.typePiece?.id === requiredTypeId
      );
    }
    if (definition.familyCode) {
      return (
        piece.typePiece?.code === requiredTypeId ||
        piece.typePieceId === requiredTypeId
      );
    }
    return false;
  });
};

const pieceOptionLabel = (piece?: PieceOption | null) => {
  if (!piece) {
    return 'Pièce';
  }
  return piece.name || 'Pièce';
};

const pieceOptionDescription = (piece?: PieceOption | null) => {
  if (!piece) {
    return '';
  }
  const parts: string[] = [];
  const typeLabel =
    piece.typePiece?.name || piece.typePiece?.code || null;
  if (typeLabel) {
    parts.push(typeLabel);
  }
  if (piece.reference) {
    parts.push(`Ref. ${piece.reference}`);
  }
  return parts.join(' • ');
};

const normalizeSelectionValue = (value: unknown) => {
  if (value === null || value === undefined || value === '') {
    return '';
  }
  if (typeof value === 'string') {
    return value;
  }
  if (typeof value === 'number') {
    return String(value);
  }
  return '';
};

watch(
  () => [props.pieces, props.assignment.pieces],
  () => {
    for (const pieceAssignment of props.assignment.pieces) {
      const options = getPieceOptions(pieceAssignment.definition);
      if (
        pieceAssignment.selectedPieceId &&
        !options.some((piece) => piece.id === pieceAssignment.selectedPieceId)
      ) {
        pieceAssignment.selectedPieceId = '';
      }
    }
  },
  { deep: true, immediate: true },
);
</script>
