import { router, protectedProcedure } from "../_core/trpc.ts";
import { z } from "zod";
import { getDb } from "../db.ts";
import { 
  adminDelegations,
  adminDelegationNotes,
  adminDelegationApprovals,
  users 
} from "../../drizzle/schema.ts";
import { eq, and, desc } from "drizzle-orm";

export const adminDelegationRouter = router({
  // Create delegation task
  createDelegation: protectedProcedure
    .input(
      z.object({
        title: z.string(),
        description: z.string().optional(),
        assigneeId: z.number(),
        priority: z.enum(["low", "medium", "high", "critical"]),
        dueDate: z.date(),
        category: z.string().optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      const result = await db.insert(adminDelegations).values({
        title: input.title,
        description: input.description,
        assigneeId: input.assigneeId,
        delegatedBy: ctx.user?.id || 0,
        priority: input.priority,
        dueDate: input.dueDate,
        category: input.category,
      });

      return {
        success: true,
        delegationId: result.insertId,
      };
    }),

  // Get delegated tasks
  getDelegatedTasks: protectedProcedure
    .input(
      z.object({
        status: z.enum(["pending", "in-progress", "completed", "cancelled"]).optional(),
        assigneeId: z.number().optional(),
      })
    )
    .query(async ({ input }) => {
      const db = await getDb();
      let query = db.select().from(adminDelegations);

      if (input.status) {
        query = query.where(eq(adminDelegations.status, input.status));
      }

      if (input.assigneeId) {
        query = query.where(eq(adminDelegations.assigneeId, input.assigneeId));
      }

      const tasks = await query.orderBy(desc(adminDelegations.createdAt));
      return tasks;
    }),

  // Update delegation status
  updateDelegationStatus: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        status: z.enum(["pending", "in-progress", "completed", "cancelled"]),
        progress: z.number().min(0).max(100).optional(),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      const updates: any = { status: input.status };
      if (input.progress !== undefined) {
        updates.progress = input.progress;
      }
      if (input.status === "completed") {
        updates.completedAt = new Date();
      }

      await db
        .update(adminDelegations)
        .set(updates)
        .where(eq(adminDelegations.id, input.delegationId));

      return { success: true };
    }),

  // Add note to delegation
  addDelegationNote: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        note: z.string(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      const result = await db.insert(adminDelegationNotes).values({
        delegationId: input.delegationId,
        authorId: ctx.user?.id || 0,
        content: input.note,
      });

      return {
        success: true,
        noteId: result.insertId,
      };
    }),

  // Complete delegation
  completeDelegation: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        verificationNotes: z.string().optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      await db
        .update(adminDelegations)
        .set({
          status: "completed",
          progress: 100,
          completedAt: new Date(),
        })
        .where(eq(adminDelegations.id, input.delegationId));

      if (input.verificationNotes) {
        await db.insert(adminDelegationNotes).values({
          delegationId: input.delegationId,
          authorId: ctx.user?.id || 0,
          content: `Verification: ${input.verificationNotes}`,
        });
      }

      return { success: true };
    }),

  // Get delegation details
  getDelegationDetails: protectedProcedure
    .input(z.object({ delegationId: z.number() }))
    .query(async ({ input }) => {
      const db = await getDb();
      const delegation = await db
        .select()
        .from(adminDelegations)
        .where(eq(adminDelegations.id, input.delegationId));

      if (!delegation.length) return null;

      const notes = await db
        .select()
        .from(adminDelegationNotes)
        .where(eq(adminDelegationNotes.delegationId, input.delegationId));

      const approvals = await db
        .select()
        .from(adminDelegationApprovals)
        .where(eq(adminDelegationApprovals.delegationId, input.delegationId));

      return {
        ...delegation[0],
        notes,
        approvals,
      };
    }),

  // Get delegation analytics
  getDelegationAnalytics: protectedProcedure.query(async () => {
    const db = await getDb();
    const allDelegations = await db.select().from(adminDelegations);

    const pending = allDelegations.filter(d => d.status === "pending").length;
    const inProgress = allDelegations.filter(d => d.status === "in-progress").length;
    const completed = allDelegations.filter(d => d.status === "completed").length;

    // Calculate average completion time
    const completedDelegations = allDelegations.filter(d => d.completedAt);
    const avgCompletionTime = completedDelegations.length > 0
      ? Math.round(
          completedDelegations.reduce((sum, d) => {
            const created = new Date(d.createdAt).getTime();
            const finished = new Date(d.completedAt!).getTime();
            return sum + (finished - created) / (1000 * 60 * 60 * 24);
          }, 0) / completedDelegations.length
        )
      : 0;

    // Calculate on-time completion
    const onTimeCount = completedDelegations.filter(d => {
      const dueDate = new Date(d.dueDate).getTime();
      const completedDate = new Date(d.completedAt!).getTime();
      return completedDate <= dueDate;
    }).length;

    const onTimeCompletion = completedDelegations.length > 0
      ? onTimeCount / completedDelegations.length
      : 0;

    return {
      totalDelegations: allDelegations.length,
      pending,
      inProgress,
      completed,
      averageCompletionTime: avgCompletionTime,
      onTimeCompletion: Math.round(onTimeCompletion * 100),
      byPriority: {
        critical: allDelegations.filter(d => d.priority === "critical").length,
        high: allDelegations.filter(d => d.priority === "high").length,
        medium: allDelegations.filter(d => d.priority === "medium").length,
        low: allDelegations.filter(d => d.priority === "low").length,
      },
    };
  }),

  // Get team members for delegation
  getTeamMembers: protectedProcedure.query(async () => {
    const db = await getDb();
    const admins = await db
      .select({
        id: users.id,
        name: users.username,
        role: users.role,
      })
      .from(users)
      .where(eq(users.role, "admin"));

    return admins.map(admin => ({
      id: admin.id,
      name: admin.name || "Unknown",
      role: admin.role || "admin",
      department: "Operations",
    }));
  }),

  // Request delegation approval
  requestDelegationApproval: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        approverIds: z.array(z.number()),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      for (const approverId of input.approverIds) {
        await db.insert(adminDelegationApprovals).values({
          delegationId: input.delegationId,
          approverId,
        });
      }

      return { success: true };
    }),

  // Approve delegation
  approveDelegation: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        approved: z.boolean(),
        comments: z.string().optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      // Find approval record
      const approval = await db
        .select()
        .from(adminDelegationApprovals)
        .where(
          and(
            eq(adminDelegationApprovals.delegationId, input.delegationId),
            eq(adminDelegationApprovals.approverId, ctx.user?.id || 0)
          )
        );

      if (approval.length > 0) {
        await db
          .update(adminDelegationApprovals)
          .set({
            status: input.approved ? "approved" : "rejected",
            comments: input.comments,
            approvedAt: new Date(),
          })
          .where(eq(adminDelegationApprovals.id, approval[0].id));
      }

      return { success: true };
    }),

  // Reassign delegation
  reassignDelegation: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        newAssigneeId: z.number(),
        reason: z.string().optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      await db
        .update(adminDelegations)
        .set({ assigneeId: input.newAssigneeId })
        .where(eq(adminDelegations.id, input.delegationId));

      if (input.reason) {
        await db.insert(adminDelegationNotes).values({
          delegationId: input.delegationId,
          authorId: ctx.user?.id || 0,
          content: `Reassigned: ${input.reason}`,
        });
      }

      return { success: true };
    }),

  // Cancel delegation
  cancelDelegation: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        reason: z.string(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      await db
        .update(adminDelegations)
        .set({ status: "cancelled" })
        .where(eq(adminDelegations.id, input.delegationId));

      await db.insert(adminDelegationNotes).values({
        delegationId: input.delegationId,
        authorId: ctx.user?.id || 0,
        content: `Cancelled: ${input.reason}`,
      });

      return { success: true };
    }),

  // Get delegation progress
  getDelegationProgress: protectedProcedure
    .input(z.object({ delegationId: z.number() }))
    .query(async ({ input }) => {
      const db = await getDb();
      const delegation = await db
        .select()
        .from(adminDelegations)
        .where(eq(adminDelegations.id, input.delegationId));

      if (!delegation.length) return null;

      const daysRemaining = Math.ceil(
        (new Date(delegation[0].dueDate).getTime() - Date.now()) / (1000 * 60 * 60 * 24)
      );

      return {
        delegationId: delegation[0].id,
        progress: delegation[0].progress,
        status: delegation[0].status,
        daysRemaining,
        isOverdue: daysRemaining < 0 && delegation[0].status !== "completed",
      };
    }),

  // Update delegation progress
  updateDelegationProgress: protectedProcedure
    .input(
      z.object({
        delegationId: z.number(),
        progress: z.number().min(0).max(100),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      await db
        .update(adminDelegations)
        .set({ progress: input.progress })
        .where(eq(adminDelegations.id, input.delegationId));

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