// src/server/features/notes/notes.routes.ts
// HTTP handlers for notes routes

import { FastifyInstance } from 'fastify';
import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';
import {
  getNotes,
  getNoteById,
  getNoteByIdWithLayout,
  createNote,
  updateNote,
  deleteNote,
  exportNotesToCSV,
  getNoteComments,
  createNoteComment,
  getNoteHistory,
  markNoteAsViewed,
} from './notes.service';
import {
  createNoteSchema,
  updateNoteSchema,
  createNoteCommentSchema,
  changeNoteStatusSchema,
  noteResponseSchema,
} from './notes.schema';
import { requireRole } from '../../shared/lib/auth';
import type { UserInfo } from '../../shared/lib/auth';
import { loggerService } from '../../shared/lib/logger';
import crypto from 'node:crypto';

// Initialize the logger
const notesLogger = loggerService.get('HTTP');

export const notesRoutes = async (fastify: FastifyInstance) => {
  const server = fastify.withTypeProvider<ZodTypeProvider>();

  // Test route for debugging parsing
  server.get('/test', async (request, reply) => {
    const body = request.body;
    return {
      success: true,
      data: { message: 'Test route working', body },
    };
  });

  // Get all notes
  server.get('/', {
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
  }, async (request: any) => {
    const user = request.user as UserInfo;
    request.log.info('GET /notes: user.id = ' + user.id);
    const notes = await getNotes(user.id);
    request.log.info('GET /notes: returning ' + notes.length + ' notes');
    return {
      success: true,
      data: notes,
    };
  });

  // Get a single note by ID
  server.get('/:id', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
    },
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
  }, async (request: any) => {
    const { id } = request.params;
    const note = await getNoteById(id);
    return {
      success: true,
      data: note,
    };
  });

  // Create note
  server.post('/', {
    schema: {
      body: createNoteSchema,
    },
    preHandler: [
      requireRole('ADMIN', 'MANAGER', 'MAID'),
      fastify.can('notes:write')
    ],
  }, async (request: any) => {
    const user = request.user as UserInfo;
    request.log.info({ body: request.body }, 'DEBUG: Incoming Note Body');
    const noteId = crypto.randomUUID();
    const body = request.body;

    // Определяем spaceId: для публичных заметок - 'public-space-id', для личных - user.id
    const spaceId = body.isPublic ? 'public-space-id' : user.id;

    request.log.info('[Routes] POST /notes: user.id=' + user.id + ', isPublic=' + body.isPublic + ', spaceId=' + spaceId);

    await createNote({
      ...body,
      id: noteId,
      authorId: user.id,
      userId: user.id,
      spaceId: spaceId,
    });

    // Get the created note with full layout and all computed fields
    // This ensures the response object contains all required fields from the contract
    const createdNote = await getNoteByIdWithLayout(noteId, user.id);

    request.log.info('[Routes] POST /notes: createdNote.id=' + createdNote.id + ', spaceId=' + createdNote.spaceId);

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

  // Update note
  server.put('/:id', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
      body: updateNoteSchema,
    },
    preHandler: [
      requireRole('ADMIN', 'MANAGER', 'MAID'),
      fastify.can('notes:write')
    ],
  }, async (request: any) => {
    const { id } = request.params;
    const user = request.user as UserInfo;
    const body = request.body;

    notesLogger.debug('[Routes] PUT /notes/' + id + ': user.id=' + user.id + ', body=', JSON.stringify(body));

    await updateNote(id, {
      ...body,
    }, user);

    // Get the updated note with personal layout coordinates
    const updatedNote = await getNoteByIdWithLayout(id, user.id);

    notesLogger.debug('[Routes] PUT /notes/' + id + ': returning updatedNote=', JSON.stringify({
      id: updatedNote.id,
      column: updatedNote.column,
      positionY: updatedNote.positionY,
      height: updatedNote.height,
      status: updatedNote.status
    }));

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

  // Delete note (soft delete)
  server.delete('/:id', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
    },
    preHandler: [
      requireRole('ADMIN', 'MANAGER'),
      fastify.can('notes:write')
    ],
  }, async (request: any) => {
    const { id } = request.params;
    const user = request.user as UserInfo;
    await deleteNote(id, user);
    
    return {
      success: true,
      message: 'Note deleted successfully',
    };
  });

  // Export notes to CSV
  server.get('/export', {
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
  }, async (request: any, reply) => {
    const user = request.user as UserInfo;
    const { csv, filename } = await exportNotesToCSV(user.id);
    
    reply
      .type('text/csv; charset=utf-8')
      .header('Content-Disposition', `attachment; filename="${filename}"`)
      .send(csv);
  });

  // Get comments for a note
  server.get('/:id/comments', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
    },
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
  }, async (request: any) => {
    const { id } = request.params;
    const comments = await getNoteComments(id);
    return {
      success: true,
      data: comments,
    };
  });

  // Create comment for a note
  server.post('/comments', {
    schema: {
      body: createNoteCommentSchema,
    },
    preHandler: [
      requireRole('ADMIN', 'MANAGER', 'MAID'),
      fastify.can('notes:write')
    ],
  }, async (request: any) => {
    const user = request.user as UserInfo;
    const body = request.body;
    
    const comment = await createNoteComment({
      noteId: body.noteId,
      content: body.content,
      authorId: user.id,
    });
    
    return {
      success: true,
      data: comment,
    };
  });

  // Get history for a note
  server.get('/:id/history', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
    },
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
  }, async (request: any) => {
    const { id } = request.params;
    const history = await getNoteHistory(id);
    return {
      success: true,
      data: history,
    };
  });

  // Change note status (status-only update with optional comment)
  server.post('/:id/status', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
      body: changeNoteStatusSchema,
    },
    preHandler: [
      requireRole('ADMIN', 'MANAGER', 'MAID'),
      fastify.can('notes:write')
    ],
  }, async (request: any) => {
    const { id } = request.params as { id: string };
    const { status, comment } = request.body as { status: any, comment?: string };
    const user = request.user as UserInfo;
    
    notesLogger.debug('[Routes] POST /notes/' + id + '/status: user.id=' + user.id + ', status=' + status + ', comment=' + comment);
    
    // Вызываем сервис обновления, передавая только статус и комментарий
    await updateNote(id, { status, comment }, user);
    
    // Возвращаем обновленную заметку с лейаутом
    const updatedNote = await getNoteByIdWithLayout(id, user.id);
    
    notesLogger.debug('[Routes] POST /notes/' + id + '/status: returning updatedNote.status=' + updatedNote.status);
    
    return {
      success: true,
      data: updatedNote,
    };
  });

  // Mark note as viewed (update lastViewedAt in note_layouts)
  server.patch('/:id/view', {
    schema: {
      params: z.object({ id: z.string().uuid() }),
    },
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
  }, async (request: any) => {
    const { id } = request.params;
    const user = request.user as UserInfo;
    
    notesLogger.debug('[Routes] PATCH /notes/' + id + '/view: user.id=' + user.id);
    
    await markNoteAsViewed(id, user.id);
    
    return {
      success: true,
      message: 'Note marked as viewed',
    };
  });
};
