import { z } from "zod";
import { COOKIE_NAME } from "@shared/const";
import { getSessionCookieOptions } from "./_core/cookies";
import { systemRouter } from "./_core/systemRouter";
import { authRouter } from "./routers/auth";
import { publicProcedure, protectedProcedure, router } from "./_core/trpc";
import { TRPCError } from "@trpc/server";
import {
  getAllProjects,
  getFeaturedProjects,
  getProjectBySlug,
  createProject,
  updateProject,
  deleteProject,
  getAllArticles,
  getRecentArticles,
  getArticleBySlug,
  createContact,
  createArticle,
  updateArticle,
  deleteArticle,
  publishArticle,
  trackArticleView,
  getArticleViewCount,
  getTopArticles,
  getViewsByDate,
  getStatsByCategory,
  getBlogStats,
} from "./db";
import { notifyOwner } from "./_core/notification";
import { sanitizeInput } from "./_core/security";

export const appRouter = router({
  system: systemRouter,

  auth: authRouter,

  // reload
  portfolio: router({
    getAll: publicProcedure.query(async () => {
      const projects = await getAllProjects(true);
      return projects.map(p => ({
        ...p,
        images: p.images ? JSON.parse(p.images) : [],
        technologies: p.technologies ? JSON.parse(p.technologies) : [],
        metrics: p.metrics ? JSON.parse(p.metrics) : null,
      }));
    }),

    getFeatured: publicProcedure.query(async () => {
      const projects = await getFeaturedProjects();
      return projects.map(p => ({
        ...p,
        images: p.images ? JSON.parse(p.images) : [],
        technologies: p.technologies ? JSON.parse(p.technologies) : [],
        metrics: p.metrics ? JSON.parse(p.metrics) : null,
      }));
    }),

    getBySlug: publicProcedure
      .input(z.object({ slug: z.string() }))
      .query(async ({ input }) => {
        const project = await getProjectBySlug(input.slug);
        if (!project) return null;

        return {
          ...project,
          images: project.images ? JSON.parse(project.images) : [],
          technologies: project.technologies ? JSON.parse(project.technologies) : [],
          metrics: project.metrics ? JSON.parse(project.metrics) : null,
        };
      }),

    getAllAdmin: protectedProcedure.query(async ({ ctx }) => {
      if (ctx.user.role !== "admin") {
        throw new TRPCError({ code: "FORBIDDEN", message: "Accès réservé aux administrateurs" });
      }
      const projects = await getAllProjects(false);
      return projects.map(p => ({
        ...p,
        images: p.images ? JSON.parse(p.images) : [],
        technologies: p.technologies ? JSON.parse(p.technologies) : [],
        metrics: p.metrics ? JSON.parse(p.metrics) : null,
      }));
    }),

    // Admin procedures
    create: protectedProcedure
      .input(
        z.object({
          slug: z.string().min(3),
          title: z.string().min(3),
          shortDescription: z.string(),
          fullDescription: z.string(),
          category: z.enum(["vitrine", "ecommerce", "webapp"]),
          sector: z.string(),
          clientName: z.string().optional(),
          clientLogo: z.string().optional(),
          mainImage: z.string().regex(/^(https?:\/\/|\/uploads\/)/, "L'URL doit commencer par http(s):// ou être une image uploadée (/uploads/)"),
          images: z.array(z.string()).optional(),
          technologies: z.array(z.string()).optional(),
          siteUrl: z.string().url().optional(),
          completionDate: z.string().optional(), // Passed as string from frontend
          testimonial: z.string().optional(),
          metrics: z.any().optional(),
          featured: z.boolean().default(false),
          published: z.boolean().default(true),
        })
      )
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Accès réservé aux administrateurs" });
        }

        const projectData: any = {
          ...input,
          title: sanitizeInput(input.title),
          shortDescription: sanitizeInput(input.shortDescription),
          fullDescription: sanitizeInput(input.fullDescription),
          sector: sanitizeInput(input.sector),
          clientName: input.clientName ? sanitizeInput(input.clientName) : undefined,
          testimonial: input.testimonial ? sanitizeInput(input.testimonial) : undefined,
          images: input.images ? JSON.stringify(input.images) : undefined,
          technologies: input.technologies ? JSON.stringify(input.technologies) : undefined,
          metrics: input.metrics ? JSON.stringify(input.metrics) : undefined,
          completionDate: input.completionDate ? new Date(input.completionDate) : undefined,
        };

        await createProject(projectData);
        return { success: true };
      }),

    update: protectedProcedure
      .input(
        z.object({
          id: z.number(),
          slug: z.string().min(3).optional(),
          title: z.string().min(3).optional(),
          shortDescription: z.string().optional(),
          fullDescription: z.string().optional(),
          category: z.enum(["vitrine", "ecommerce", "webapp"]).optional(),
          sector: z.string().optional(),
          clientName: z.string().optional(),
          clientLogo: z.string().optional(),
          mainImage: z.string().regex(/^(https?:\/\/|\/uploads\/)/, "L'URL doit commencer par http(s):// ou être une image uploadée (/uploads/)"),
          images: z.array(z.string()).optional(),
          technologies: z.array(z.string()).optional(),
          siteUrl: z.string().url().optional(),
          completionDate: z.string().optional(),
          testimonial: z.string().optional(),
          metrics: z.any().optional(),
          featured: z.boolean().optional(),
          published: z.boolean().optional(),
        })
      )
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Accès réservé aux administrateurs" });
        }

        const { id, ...updates } = input;
        const projectUpdates: any = { ...updates };

        if (updates.title) projectUpdates.title = sanitizeInput(updates.title);
        if (updates.shortDescription) projectUpdates.shortDescription = sanitizeInput(updates.shortDescription);
        if (updates.fullDescription) projectUpdates.fullDescription = sanitizeInput(updates.fullDescription);
        if (updates.sector) projectUpdates.sector = sanitizeInput(updates.sector);
        if (updates.clientName) projectUpdates.clientName = sanitizeInput(updates.clientName);
        if (updates.testimonial) projectUpdates.testimonial = sanitizeInput(updates.testimonial);

        if (updates.images) projectUpdates.images = JSON.stringify(updates.images);
        if (updates.technologies) projectUpdates.technologies = JSON.stringify(updates.technologies);
        if (updates.metrics) projectUpdates.metrics = JSON.stringify(updates.metrics);
        if (updates.completionDate) projectUpdates.completionDate = new Date(updates.completionDate);

        await updateProject(id, projectUpdates);
        return { success: true };
      }),

    delete: protectedProcedure
      .input(z.object({ id: z.number() }))
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Accès réservé aux administrateurs" });
        }

        await deleteProject(input.id);
        return { success: true };
      }),
  }),

  blog: router({
    getAll: publicProcedure.query(async () => {
      const articles = await getAllArticles(true);
      return articles.map(a => ({
        ...a,
        tags: a.tags ? JSON.parse(a.tags) : [],
        seoKeywords: a.seoKeywords ? JSON.parse(a.seoKeywords) : [],
      }));
    }),

    getRecent: publicProcedure
      .input(z.object({ limit: z.number().default(3) }).optional())
      .query(async ({ input }) => {
        const articles = await getRecentArticles(input?.limit || 3);
        return articles.map(a => ({
          ...a,
          tags: a.tags ? JSON.parse(a.tags) : [],
          seoKeywords: a.seoKeywords ? JSON.parse(a.seoKeywords) : [],
        }));
      }),

    getBySlug: publicProcedure
      .input(z.object({ slug: z.string() }))
      .query(async ({ input }) => {
        const article = await getArticleBySlug(input.slug);
        if (!article) return null;

        return {
          ...article,
          tags: article.tags ? JSON.parse(article.tags) : [],
          seoKeywords: article.seoKeywords ? JSON.parse(article.seoKeywords) : [],
        };
      }),

    getAllAdmin: protectedProcedure.query(async ({ ctx }) => {
      if (ctx.user.role !== "admin") {
        throw new TRPCError({ code: "FORBIDDEN", message: "Accès réservé aux administrateurs" });
      }
      const articles = await getAllArticles(false);
      return articles.map(a => ({
        ...a,
        tags: a.tags ? JSON.parse(a.tags) : [],
        seoKeywords: a.seoKeywords ? JSON.parse(a.seoKeywords) : [],
      }));
    }),

    // Admin procedures
    create: protectedProcedure
      .input(
        z.object({
          title: z.string().min(5, "Le titre doit contenir au moins 5 caract\u00e8res"),
          slug: z.string().min(3, "Le slug doit contenir au moins 3 caract\u00e8res"),
          excerpt: z.string().min(20, "L'extrait doit contenir au moins 20 caract\u00e8res"),
          content: z.string().min(100, "Le contenu doit contenir au moins 100 caract\u00e8res"),
          heroImage: z.string().regex(/^(https?:\/\/|\/uploads\/)/, "L'URL doit commencer par http(s):// ou être une image uploadée (/uploads/)"),
          category: z.string(),
          tags: z.array(z.string()),
          author: z.string().default("Leifo"),
          readingTime: z.number().positive(),
          seoTitle: z.string().optional(),
          seoDescription: z.string().optional(),
          seoKeywords: z.array(z.string()).optional(),
          published: z.boolean().default(false),
        })
      )
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }

        const articleData: any = {
          ...input,
          title: sanitizeInput(input.title),
          excerpt: sanitizeInput(input.excerpt),
          content: sanitizeInput(input.content), // Markdown content escaping
          category: sanitizeInput(input.category),
          author: sanitizeInput(input.author),
          seoTitle: input.seoTitle ? sanitizeInput(input.seoTitle) : undefined,
          seoDescription: input.seoDescription ? sanitizeInput(input.seoDescription) : undefined,
          tags: JSON.stringify(input.tags),
          seoKeywords: input.seoKeywords ? JSON.stringify(input.seoKeywords) : undefined,
          publishedAt: input.published ? new Date() : undefined,
        };
        const articleId = await createArticle(articleData);

        return { success: true, id: articleId };
      }),

    update: protectedProcedure
      .input(
        z.object({
          id: z.number(),
          title: z.string().min(5).optional(),
          slug: z.string().min(3).optional(),
          excerpt: z.string().min(20).optional(),
          content: z.string().min(100).optional(),
          heroImage: z.string().regex(/^(https?:\/\/|\/uploads\/)/, "L'URL doit commencer par http(s):// ou être une image uploadée (/uploads/)").optional(),
          category: z.string().optional(),
          tags: z.array(z.string()).optional(),
          author: z.string().optional(),
          readingTime: z.number().positive().optional(),
          seoTitle: z.string().optional(),
          seoDescription: z.string().optional(),
          seoKeywords: z.array(z.string()).optional(),
        })
      )
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }

        const { id, ...updates } = input;
        const processedUpdates: any = { ...updates };

        if (updates.title) processedUpdates.title = sanitizeInput(updates.title);
        if (updates.excerpt) processedUpdates.excerpt = sanitizeInput(updates.excerpt);
        if (updates.content) processedUpdates.content = sanitizeInput(updates.content);
        if (updates.category) processedUpdates.category = sanitizeInput(updates.category);
        if (updates.author) processedUpdates.author = sanitizeInput(updates.author);
        if (updates.seoTitle) processedUpdates.seoTitle = sanitizeInput(updates.seoTitle);
        if (updates.seoDescription) processedUpdates.seoDescription = sanitizeInput(updates.seoDescription);

        if (updates.tags) {
          processedUpdates.tags = JSON.stringify(updates.tags);
        }
        if (updates.seoKeywords) {
          processedUpdates.seoKeywords = JSON.stringify(updates.seoKeywords);
        }

        await updateArticle(id, processedUpdates);
        return { success: true };
      }),

    delete: protectedProcedure
      .input(z.object({ id: z.number() }))
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }

        await deleteArticle(input.id);
        return { success: true };
      }),

    publish: protectedProcedure
      .input(z.object({ id: z.number(), published: z.boolean() }))
      .mutation(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }

        await publishArticle(input.id, input.published);
        return { success: true };
      }),

    // Analytics endpoints
    trackView: publicProcedure
      .input(z.object({
        articleId: z.number(),
        userAgent: z.string().optional(),
        referrer: z.string().optional(),
      }))
      .mutation(async ({ input }) => {
        await trackArticleView({
          articleId: input.articleId,
          userAgent: input.userAgent || null,
          ipHash: null, // Could hash IP for privacy if needed
          referrer: input.referrer || null,
        });
        return { success: true };
      }),

    getViewCount: publicProcedure
      .input(z.object({ articleId: z.number() }))
      .query(async ({ input }) => {
        const count = await getArticleViewCount(input.articleId);
        return { count };
      }),

    getStats: protectedProcedure
      .query(async ({ ctx }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }
        return await getBlogStats();
      }),

    getTopArticles: protectedProcedure
      .input(z.object({ limit: z.number().default(10) }).optional())
      .query(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }
        const articles = await getTopArticles(input?.limit || 10);
        return articles.map(a => ({
          ...a,
          tags: a.tags ? JSON.parse(a.tags) : [],
          seoKeywords: a.seoKeywords ? JSON.parse(a.seoKeywords) : [],
        }));
      }),

    getViewsByDate: protectedProcedure
      .input(z.object({ days: z.number().default(30) }).optional())
      .query(async ({ ctx, input }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }
        return await getViewsByDate(input?.days || 30);
      }),

    getStatsByCategory: protectedProcedure
      .query(async ({ ctx }) => {
        if (ctx.user.role !== "admin") {
          throw new TRPCError({ code: "FORBIDDEN", message: "Acc\u00e8s r\u00e9serv\u00e9 aux administrateurs" });
        }
        return await getStatsByCategory();
      }),
  }),

  contact: router({
    submit: publicProcedure
      .input(
        z.object({
          name: z.string().min(3, "Le nom doit contenir au moins 3 caractères"),
          email: z.string().email("Email invalide"),
          phone: z.string().optional(),
          projectType: z.enum(["vitrine", "ecommerce", "webapp", "autre"]),
          message: z.string().min(20, "Le message doit contenir au moins 20 caractères"),
          newsletter: z.boolean().default(false),
        })
      )
      .mutation(async ({ input }) => {
        try {
          // Strict Sanitation
          const safeInput = {
            ...input,
            name: sanitizeInput(input.name),
            message: sanitizeInput(input.message),
            // Email validé par Zod, mais on escape pour l'affichage/stockage sûr
            email: sanitizeInput(input.email),
            phone: input.phone ? sanitizeInput(input.phone) : undefined,
          };

          // Save to DB
          await createContact({
            name: safeInput.name,
            email: safeInput.email,
            phone: safeInput.phone || null,
            projectType: safeInput.projectType,
            message: safeInput.message,
            newsletter: safeInput.newsletter,
            status: "new",
          });

          // Send Email via Nodemailer
          try {
            const { sendContactEmail } = await import("./_core/email");
            await sendContactEmail({
              name: safeInput.name,
              email: input.email, // Use original email for delivery to ensure validity
              phone: safeInput.phone || null,
              projectType: safeInput.projectType,
              message: safeInput.message,
              newsletter: safeInput.newsletter,
            });
          } catch (emailError) {
            console.error("Failed to send email:", emailError);
          }

          // Notify owner
          try {
            await notifyOwner({
              title: "Nouveau contact - Leifo",
              content: `Nouveau message de ${safeInput.name} (${safeInput.email}) pour un projet ${safeInput.projectType}. Message: ${safeInput.message.substring(0, 100)}...`,
            });
          } catch (notifyError) {
            console.warn("Internal notification skipped:", notifyError);
          }

          return { success: true };
        } catch (error) {
          console.error("Error submitting contact:", error);
          throw new Error("Erreur lors de l'envoi du message");
        }
      }),
  }),
});

export type AppRouter = typeof appRouter;
