import { router, protectedProcedure } from '@/src/trpc/trpc-index'
import { z } from 'zod';
import { ApiError } from '@/src/lib/api-error'
import { extractKeyFromPresignedUrl, deleteImageUtil, scaffoldAssetUrl } from '@/src/lib/s3-client'
import { scheduleStoreInitialization } from '@/src/stores/store-initializer'
import {
  getAllStores as getAllStoresFromDb,
  getStoreById as getStoreByIdFromDb,
  createStore as createStoreInDb,
  updateStore as updateStoreInDb,
  deleteStore as deleteStoreFromDb,
} from '@/src/dbService'
import type { Store } from '@packages/shared'

export const storeRouter = router({
  getStores: protectedProcedure
    .query(async ({ ctx }): Promise<{ stores: any[]; count: number }> => {
      const stores = await getAllStoresFromDb();

      await Promise.all(stores.map(async store => {
        if(store.imageUrl)
        store.imageUrl = scaffoldAssetUrl(store.imageUrl)
      })).catch((e) => {
        throw new ApiError("Unable to find store image urls")
      })

      return {
        stores,
        count: stores.length,
      };
    }),

  getStoreById: protectedProcedure
    .input(z.object({
      id: z.number(),
    }))
    .query(async ({ input, ctx }): Promise<{ store: any }> => {
      const { id } = input;

      const store = await getStoreByIdFromDb(id);

      if (!store) {
        throw new ApiError("Store not found", 404);
      }
      store.imageUrl = scaffoldAssetUrl(store.imageUrl);
      return {
        store,
      };
    }),

  createStore: protectedProcedure
    .input(z.object({
      name: z.string().min(1, "Name is required"),
      description: z.string().optional(),
      imageUrl: z.string().optional(),
      owner: z.number().min(1, "Owner is required"),
      products: z.array(z.number()).optional(),
    }))
    .mutation(async ({ input, ctx }): Promise<{ store: Store; message: string }> => {
      const { name, description, imageUrl, owner, products } = input;

      const imageKey = imageUrl ? extractKeyFromPresignedUrl(imageUrl) : undefined;

      const newStore = await createStoreInDb(
        {
          name,
          description,
          imageUrl: imageKey,
          owner,
        },
        products
      );

      /*
      // Old implementation - direct DB query:
      const [newStore] = await db
        .insert(storeInfo)
        .values({
          name,
          description,
          imageUrl: imageKey,
          owner,
        })
        .returning();

      // Assign selected products to this store
      if (products && products.length > 0) {
        await db
          .update(productInfo)
          .set({ storeId: newStore.id })
          .where(inArray(productInfo.id, products));
      }
      */

      // Reinitialize stores to reflect changes
      await scheduleStoreInitialization()

      return {
        store: newStore,
        message: "Store created successfully",
      };
    }),

  updateStore: protectedProcedure
    .input(z.object({
      id: z.number(),
      name: z.string().min(1, "Name is required"),
      description: z.string().optional(),
      imageUrl: z.string().optional(),
      owner: z.number().min(1, "Owner is required"),
      products: z.array(z.number()).optional(),
    }))
    .mutation(async ({ input, ctx }): Promise<{ store: Store; message: string }> => {
      const { id, name, description, imageUrl, owner, products } = input;

      const existingStore = await getStoreByIdFromDb(id);

      if (!existingStore) {
        throw new ApiError("Store not found", 404);
      }

      const oldImageKey = existingStore.imageUrl;
      const newImageKey = imageUrl ? extractKeyFromPresignedUrl(imageUrl) : oldImageKey;

      // Delete old image only if:
      // 1. New image provided and keys are different, OR
      // 2. No new image but old exists (clearing the image)
      if (oldImageKey && (
        (newImageKey && newImageKey !== oldImageKey) ||
        (!newImageKey)
      )) {
        try {
          await deleteImageUtil({keys: [oldImageKey]});
        } catch (error) {
          console.error('Failed to delete old image:', error);
          // Continue with update even if deletion fails
        }
      }

      const updatedStore = await updateStoreInDb(
        id,
        {
          name,
          description,
          imageUrl: newImageKey,
          owner,
        },
        products
      );

      /*
      // Old implementation - direct DB query:
      const [updatedStore] = await db
        .update(storeInfo)
        .set({
          name,
          description,
          imageUrl: newImageKey,
          owner,
        })
        .where(eq(storeInfo.id, id))
        .returning();

      if (!updatedStore) {
        throw new ApiError("Store not found", 404);
      }

      // Update products if provided
      if (products) {
        // First, set storeId to null for products not in the list but currently assigned to this store
        await db
          .update(productInfo)
          .set({ storeId: null })
          .where(eq(productInfo.storeId, id));

        // Then, assign the selected products to this store
        if (products.length > 0) {
          await db
            .update(productInfo)
            .set({ storeId: id })
            .where(inArray(productInfo.id, products));
        }
      }
      */

      // Reinitialize stores to reflect changes
      await scheduleStoreInitialization()

      return {
        store: updatedStore,
        message: "Store updated successfully",
      };
    }),

  deleteStore: protectedProcedure
    .input(z.object({
      storeId: z.number(),
    }))
    .mutation(async ({ input, ctx }): Promise<{ message: string }> => {
      const { storeId } = input;

      const result = await deleteStoreFromDb(storeId);

      /*
      // Old implementation - direct DB query with transaction:
      const result = await db.transaction(async (tx) => {
        // First, update all products of this store to set storeId to null
        await tx
          .update(productInfo)
          .set({ storeId: null })
          .where(eq(productInfo.storeId, storeId));

        // Then delete the store
        const [deletedStore] = await tx
          .delete(storeInfo)
          .where(eq(storeInfo.id, storeId))
          .returning();

        if (!deletedStore) {
          throw new ApiError("Store not found", 404);
        }

        return {
          message: "Store deleted successfully",
        };
      });
      */

      // Reinitialize stores to reflect changes (outside transaction)
      await scheduleStoreInitialization()

      return result;
    }),
});
