/** * EntityGrid.vue - Unified entity grid layout component * * Extracted from
GiftedDialog.vue to provide a reusable grid layout * for displaying people,
projects, and special entities with selection. * * @author Matthew Raymer */
<template>
  <ul :class="gridClasses">
    <!-- Special entities (You, Unnamed) for people grids -->
    <template v-if="entityType === 'people'">
      <!-- "You" entity -->
      <SpecialEntityCard
        v-if="showYouEntity"
        entity-type="you"
        label="You"
        icon="hand"
        :selectable="youSelectable"
        :conflicted="youConflicted"
        :entity-data="youEntityData"
        :notify="notify"
        :conflict-context="conflictContext"
        @entity-selected="handleEntitySelected"
      />

      <!-- "Unnamed" entity -->
      <SpecialEntityCard
        entity-type="unnamed"
        label="Unnamed"
        icon="circle-question"
        :entity-data="unnamedEntityData"
        :notify="notify"
        :conflict-context="conflictContext"
        @entity-selected="handleEntitySelected"
      />
    </template>

    <!-- Empty state message -->
    <li v-if="entities.length === 0" :class="emptyStateClasses">
      {{ emptyStateMessage }}
    </li>

    <!-- Entity cards (people or projects) -->
    <template v-if="entityType === 'people'">
      <PersonCard
        v-for="person in displayedEntities as Contact[]"
        :key="person.did"
        :person="person"
        :conflicted="isPersonConflicted(person.did)"
        :show-time-icon="true"
        :notify="notify"
        :conflict-context="conflictContext"
        @person-selected="handlePersonSelected"
      />
    </template>

    <template v-else-if="entityType === 'projects'">
      <ProjectCard
        v-for="project in displayedEntities as PlanData[]"
        :key="project.handleId"
        :project="project"
        :active-did="activeDid"
        :all-my-dids="allMyDids"
        :all-contacts="allContacts"
        :notify="notify"
        :conflict-context="conflictContext"
        @project-selected="handleProjectSelected"
      />
    </template>

    <!-- Show All navigation -->
    <ShowAllCard
      v-if="shouldShowAll"
      :entity-type="entityType"
      :route-name="showAllRoute"
      :query-params="showAllQueryParams"
    />
  </ul>
</template>

<script lang="ts">
import { Component, Prop, Vue, Emit } from "vue-facing-decorator";
import PersonCard from "./PersonCard.vue";
import ProjectCard from "./ProjectCard.vue";
import SpecialEntityCard from "./SpecialEntityCard.vue";
import ShowAllCard from "./ShowAllCard.vue";
import { Contact } from "../db/tables/contacts";
import { PlanData } from "../interfaces/records";
import { NotificationIface } from "../constants/app";

/**
 * EntityGrid - Unified grid layout for displaying people or projects
 *
 * Features:
 * - Responsive grid layout for people/projects
 * - Special entity integration (You, Unnamed)
 * - Conflict detection integration
 * - Empty state messaging
 * - Show All navigation
 * - Event delegation for entity selection
 * - Warning notifications for conflicted entities
 * - Template streamlined with computed CSS properties
 * - Configurable entity display logic via function props
 */
@Component({
  components: {
    PersonCard,
    ProjectCard,
    SpecialEntityCard,
    ShowAllCard,
  },
})
export default class EntityGrid extends Vue {
  /** Type of entities to display */
  @Prop({ required: true })
  entityType!: "people" | "projects";

  /** Array of entities to display */
  @Prop({ required: true })
  entities!: Contact[] | PlanData[];

  /** Maximum number of entities to display */
  @Prop({ default: 10 })
  maxItems!: number;

  /** Active user's DID */
  @Prop({ required: true })
  activeDid!: string;

  /** All user's DIDs */
  @Prop({ required: true })
  allMyDids!: string[];

  /** All contacts */
  @Prop({ required: true })
  allContacts!: Contact[];

  /** Function to check if a person DID would create a conflict */
  @Prop({ required: true })
  conflictChecker!: (did: string) => boolean;

  /** Whether to show the "You" entity for people grids */
  @Prop({ default: true })
  showYouEntity!: boolean;

  /** Whether the "You" entity is selectable */
  @Prop({ default: true })
  youSelectable!: boolean;

  /** Route name for "Show All" navigation */
  @Prop({ default: "" })
  showAllRoute!: string;

  /** Query parameters for "Show All" navigation */
  @Prop({ default: () => ({}) })
  showAllQueryParams!: Record<string, string>;

  /** Notification function from parent component */
  @Prop()
  notify?: (notification: NotificationIface, timeout?: number) => void;

  /** Context for conflict messages (e.g., "giver", "recipient") */
  @Prop({ default: "other party" })
  conflictContext!: string;

  /**
   * Function to determine which entities to display (allows parent control)
   *
   * This function prop allows parent components to customize which entities
   * are displayed in the grid, enabling advanced filtering, sorting, and
   * display logic beyond the default simple slice behavior.
   *
   * @param entities - The full array of entities (Contact[] or PlanData[])
   * @param entityType - The type of entities being displayed ("people" or "projects")
   * @param maxItems - The maximum number of items to display (from maxItems prop)
   * @returns Filtered/sorted array of entities to display
   *
   * @example
   * // Custom filtering: only show contacts with profile images
   * :display-entities-function="(entities, type, max) =>
   *   entities.filter(e => e.profileImageUrl).slice(0, max)"
   *
   * @example
   * // Custom sorting: sort projects by name
   * :display-entities-function="(entities, type, max) =>
   *   entities.sort((a, b) => a.name.localeCompare(b.name)).slice(0, max)"
   *
   * @example
   * // Advanced logic: different limits for different entity types
   * :display-entities-function="(entities, type, max) =>
   *   type === 'projects' ? entities.slice(0, 5) : entities.slice(0, max)"
   */
  @Prop({ default: null })
  displayEntitiesFunction?: (
    entities: Contact[] | PlanData[],
    entityType: "people" | "projects",
    maxItems: number,
  ) => Contact[] | PlanData[];

  /**
   * CSS classes for the empty state message
   */
  get emptyStateClasses(): string {
    return "text-xs text-slate-500 italic col-span-full";
  }

  /**
   * Computed CSS classes for the grid layout
   */
  get gridClasses(): string {
    const baseClasses = "grid gap-x-2 gap-y-4 text-center mb-4";

    if (this.entityType === "projects") {
      return `${baseClasses} grid-cols-3 md:grid-cols-4`;
    } else {
      return `${baseClasses} grid-cols-4 sm:grid-cols-5 md:grid-cols-6`;
    }
  }

  /**
   * Computed entities to display - uses function prop if provided, otherwise defaults
   */
  get displayedEntities(): Contact[] | PlanData[] {
    if (this.displayEntitiesFunction) {
      return this.displayEntitiesFunction(
        this.entities,
        this.entityType,
        this.maxItems,
      );
    }

    // Default implementation for backward compatibility
    const maxDisplay = this.entityType === "projects" ? 7 : this.maxItems;
    return this.entities.slice(0, maxDisplay);
  }

  /**
   * Computed empty state message based on entity type
   */
  get emptyStateMessage(): string {
    if (this.entityType === "projects") {
      return "(No projects found.)";
    } else {
      return "(Add friends to see more people worthy of recognition.)";
    }
  }

  /**
   * Whether to show the "Show All" navigation
   */
  get shouldShowAll(): boolean {
    return this.entities.length > 0 && this.showAllRoute !== "";
  }

  /**
   * Whether the "You" entity is conflicted
   */
  get youConflicted(): boolean {
    return this.conflictChecker(this.activeDid);
  }

  /**
   * Entity data for the "You" special entity
   */
  get youEntityData(): { did: string; name: string } {
    return {
      did: this.activeDid,
      name: "You",
    };
  }

  /**
   * Entity data for the "Unnamed" special entity
   */
  get unnamedEntityData(): { did: string; name: string } {
    return {
      did: "",
      name: "Unnamed",
    };
  }

  /**
   * Check if a person DID is conflicted
   */
  isPersonConflicted(did: string): boolean {
    return this.conflictChecker(did);
  }

  /**
   * Handle person selection from PersonCard
   */
  handlePersonSelected(person: Contact): void {
    this.emitEntitySelected({
      type: "person",
      data: person,
    });
  }

  /**
   * Handle project selection from ProjectCard
   */
  handleProjectSelected(project: PlanData): void {
    this.emitEntitySelected({
      type: "project",
      data: project,
    });
  }

  /**
   * Handle special entity selection from SpecialEntityCard
   */
  handleEntitySelected(event: {
    type: string;
    entityType: string;
    data: { did?: string; name: string };
  }): void {
    this.emitEntitySelected({
      type: "special",
      entityType: event.entityType,
      data: event.data,
    });
  }

  // Emit methods using @Emit decorator

  @Emit("entity-selected")
  emitEntitySelected(data: {
    type: "person" | "project" | "special";
    entityType?: string;
    data: Contact | PlanData | { did?: string; name: string };
  }): {
    type: "person" | "project" | "special";
    entityType?: string;
    data: Contact | PlanData | { did?: string; name: string };
  } {
    return data;
  }
}
</script>

<style scoped>
/* Grid-specific styles if needed */
</style>
