import { defineStore } from 'pinia';
import { API } from '../Api';
import { useLoader } from '../composables/use-loader';

// --- Type Definitions ---

type TableData = Record<string, Record<string | number, any>>;

interface HeaderInfo {
  manual: number;
  pending: number;
}

interface CellUpdatePayload {
    primaryId: string | number;
    primaryIdColumn: string;
    secondaryId: string | number;
    secondaryIdColumn: string;
    field: string;
    newValue: any;
}

// Define the complete state shape
interface TableState {
  // Core Data
  fullTableData: TableData;
  loading: boolean;
  
  // Application Metadata
  idOccurrencesData: Record<string, number>;
  idList: (string | number)[];
  primaryIdName: string;
  secondaryIdName: string;
  primaryTableKeys: string[];
  secondaryTableKeys: string[];
  extraColsPrimary: string[];
  extraColsSecondary: string[];
  reconciliationType: string | null;

  // Shared UI State
  selected_id: string | number | null;
}

// --- Store Definition ---

export const useTableStore = defineStore('table', {
  /**
   * The core data, metadata, and UI state for the application.
   */
  state: (): TableState => ({
    // Core Data
    fullTableData: {},
    loading: false,

    // Application Metadata
    idOccurrencesData: {},
    idList: [],
    primaryIdName: 'id_name', // A sensible default
    secondaryIdName: '',
    primaryTableKeys: [],
    secondaryTableKeys: [],
    extraColsPrimary: [],
    extraColsSecondary: [],
    reconciliationType: null,

    // Shared UI State
    selected_id: null,
  }),

  /**
   * Derived state (computed properties).
   */
  getters: {
    /**
     * Calculates header counts from the full dataset.
     * Updates automatically whenever 'fullTableData' changes.
     */
    headerInfo(state): HeaderInfo {
      const matchColumn = state.fullTableData['Match'];
      if (!matchColumn) {
        return { manual: 0, pending: 0 };
      }

      let manualCount = 0;
      let pendingCount = 0;

      for (const status of Object.values(matchColumn)) {
        if (status === 'Approved') {
          manualCount++;
        } else if (status === 'Pending') {
          pendingCount++;
        }
      }

      return { manual: manualCount, pending: pendingCount };
    }
  },

  /**
   * Actions that mutate the state.
   */
  actions: {
    /**
     * Fetches the main table data from the backend.
     */
    async fetchTableData() {
      this.loading = true;
      const loader = useLoader("Loading data..");
      loader.show();

      try {
        const responseTable = await API.postTable({
          "dataset_name": "webapp_dataset",
          "chunksize": 10000,
          "chunk_index": 0,
          "filters": {},
          "group_keys": [],
          "group_rows": [],
          "sort_model": [],
          "custom_filters": {}
        });
        this.fullTableData = responseTable.data;
        
      } catch (error) {
        console.error("Failed to fetch table data:", error);
      } finally {
        this.loading = false;
        loader.hide();
      }
    },

    /**
     * Fetches all one-time application metadata (IDs, keys, etc.).
     * This is called once by the parent component on mount.
     */
    async fetchMetadata() {
      try {
        // Fetch all metadata in parallel
        const [
          idOccurencesRes,
          idListRes,
          primaryIdRes,
          secondaryIdRes,
          keysInfoRes,
          extraColsRes,
          reconciliationTypeRes
        ] = await Promise.all([
          API.getIdOccurences(),
          API.getIdList(),
          API.getPrimaryIdName(),
          API.getSecondaryIdName(),
          API.getKeysInfos(),
          API.getExtraCols(),
          API.getReconciliationType()
        ]);

        // --- Commit all data to the store ---
        this.idOccurrencesData = idOccurencesRes.data.id_occurrences;
        this.idList = idListRes.data.id_list.sort((a: any, b: any) => {
          return isNaN(a) || isNaN(b) ? a.localeCompare(b) : a - b;
        });
        this.primaryIdName = primaryIdRes.data.primary_id_name;
        this.secondaryIdName = secondaryIdRes.data.secondary_id_name;
        this.extraColsPrimary = extraColsRes.data.extra_cols_primary;
        this.extraColsSecondary = extraColsRes.data.extra_cols_secondary;
        this.reconciliationType = reconciliationTypeRes.data.reconciliation_type;
        
        this.primaryTableKeys = [
          this.primaryIdName,
          ...keysInfoRes.data.primary_keys
        ];
        this.secondaryTableKeys = [
          this.secondaryIdName,
          ...keysInfoRes.data.secondary_keys.map((key: string) => `secondary_${key}`), 
          "Match", "Match score", "Comments"
        ];

        // --- Set the initial selected_id ---
        if (this.idList.length > 0) {
          this.selected_id = this.idList[0];
        }
        
      } catch (error) {
        console.error("Failed to fetch app metadata:", error);
      }
    },

    /**
     * Updates a cell and applies reconciliation logic ('one_to_one' or 'one_to_many').
     */
    updateCell(payload: CellUpdatePayload) {
      const { primaryId, primaryIdColumn, secondaryId, secondaryIdColumn, field, newValue } = payload;

      const primaryIdCol = this.fullTableData[primaryIdColumn];
      const secondaryIdCol = this.fullTableData[secondaryIdColumn];
      const targetFieldCol = this.fullTableData[field];

      if (!primaryIdCol || !secondaryIdCol || !targetFieldCol) {
        console.error("CRITICAL: One of the columns was not found in fullTableData.", {
            primaryIdColumn,
            secondaryIdColumn,
            field
        });
        return;
      }

      // --- 1. Find the index of the row the user just changed ---
      let targetIndex = "-1"; // Use string to match object keys
      for (const index in primaryIdCol) {
        if (
            String(primaryIdCol[index]) === String(primaryId) &&
            String(secondaryIdCol[index]) === String(secondaryId)
        ) {
            targetIndex = index;
            break;
        }
      }

      if (targetIndex !== "-1") {
        
        // --- 2. Apply the user's requested change to a new state object ---
        // We start with a copy that we can mutate.
        let newFullTableData = {
            ...this.fullTableData,
            [field]: {
                ...this.fullTableData[field],
                [targetIndex]: newValue,
            },
        };

        // --- 3. Check for special business logic ---
        const isMatchField = field === 'Match';
        const isApproved = newValue === 'Approved';

        // Only run if the user just Approved a Match
        if (isMatchField && isApproved) {
          
          // Get a mutable copy of the 'Match' column *after* the initial change
          let newMatchCol = { ...newFullTableData['Match'] };
          let changesMade = false;
          
          // Get the data columns we'll need for comparisons
          const currentPrimaryIdCol = newFullTableData[primaryIdColumn];
          const currentSecondaryIdCol = newFullTableData[secondaryIdColumn];

          // --- LOGIC BLOCK A: 'one_to_one' ---
          if (this.reconciliationType === 'one_to_one') {
            for (const index in newMatchCol) {
              if (index === targetIndex) continue; // Skip the row we just approved
              
              const isPending = newMatchCol[index] === 'Pending';
              
              // Only check 'Pending' rows
              if (isPending) {
                // Find other rows with the SAME primaryId
                const isSamePrimary = String(currentPrimaryIdCol[index]) === String(primaryId);
                
                // Find other rows with the SAME secondaryId
                const isSameSecondary = String(currentSecondaryIdCol[index]) === String(secondaryId);

                // --- KEY CHANGE ---
                // If it's pending AND shares EITHER the primary or secondary ID, reject it.
                if (isSamePrimary || isSameSecondary) {
                  newMatchCol[index] = 'Rejected';
                  changesMade = true;
                }
              }
            }
          } 
          
          // --- LOGIC BLOCK B: 'one_to_many' ---
          else if (this.reconciliationType === 'one_to_many') {
            for (const index in newMatchCol) {
              if (index === targetIndex) continue; // Skip the row we just approved
              
              // Find other rows with the SAME secondaryId
              const isSameSecondary = String(currentSecondaryIdCol[index]) === String(secondaryId);
              const isPending = newMatchCol[index] === 'Pending';

              if (isSameSecondary && isPending) {
                newMatchCol[index] = 'Rejected';
                changesMade = true;
              }
            }
          }

          // --- 4. If any logic block made changes, update our state object ---
          if (changesMade) {
            newFullTableData = {
                ...newFullTableData,
                'Match': newMatchCol,
            };
          }
        }

        // --- 5. Commit the final state (with all changes) to the store ---
        this.fullTableData = newFullTableData;

      } else {
        console.warn("❌ Store failed to find matching row to update.", payload);
      }
    },

    // --- UI State Actions ---

    /** Sets the currently selected ID for the focus tab. */
    setSelectedId(id: string | number) {
      this.selected_id = id;
    },

    /** Selects the next ID in the list. */
    nextId() {
      if (this.selected_id === null) return;
      const currentIndex = this.idList.indexOf(this.selected_id);
      if (currentIndex >= 0 && currentIndex < this.idList.length - 1) {
        this.selected_id = this.idList[currentIndex + 1];
      }
    },

    /** Selects the previous ID in the list. */
    previousId() {
      if (this.selected_id === null) return;
      const currentIndex = this.idList.indexOf(this.selected_id);
      if (currentIndex > 0) {
        this.selected_id = this.idList[currentIndex - 1];
      }
    },
  }
});