// src/client/shared/api/repositories/NoteRepository.ts
// Note Repository with Zod validation for notes API

import { z } from 'zod';
import { BaseRepository } from '../BaseRepository';
import type { RequestConfig } from '../api.client';

/**
 * Zod-схемы для валидации запросов/ответов (синхронизированы с бэкендом)
 */

// Enums
export const notePriorityEnum = z.enum(['low', 'normal', 'high']);
export const noteStatusEnum = z.enum(['active', 'done', 'cancelled']); // deferred removed - now using personal reminders in note_layouts
export const noteHistoryActionEnum = z.enum(['created', 'updated', 'status_changed', 'commented', 'returned', 'priority_changed']);

// Note Response
export const noteResponseSchema = z.object({
  id: z.string(),
  title: z.string(),
  content: z.string(),
  authorId: z.string(),
  authorName: z.string().nullable().optional(),
  userId: z.string(),
  spaceId: z.string(),
  priority: notePriorityEnum,
  status: noteStatusEnum,
  isPublic: z.boolean(),
  isAuthority: z.boolean().optional(),
  layout: z.object({
    id: z.string(),
    noteId: z.string(),
    userId: z.string(),
    column: z.number().int().min(1).max(6),
    positionY: z.number().int().min(0),
    height: z.number().int().min(65).max(1000),
    reminderAt: z.string().datetime().nullable(),
    lastViewedAt: z.string().datetime().nullable(),
    createdAt: z.string().datetime(),
    updatedAt: z.string().datetime(),
  }).nullable(),
  createdAt: z.string().datetime(),
  updatedAt: z.string().datetime(),
  archivedAt: z.string().datetime().nullable(),
  lastCommentAt: z.string().datetime().nullable(),
  lastCommentAuthorId: z.string().uuid().nullable(),
  priorityUpdatedAt: z.string().datetime().nullable(),
  lastPriorityAuthorId: z.string().uuid().nullable(),
  lastMentionAt: z.string().datetime().nullable(), // Personal mention timestamp (computed on backend) - ISO format from backend
  statusChangeReason: z.string().nullable().optional(),
});

// Note Comment Response
export const noteCommentResponseSchema = z.object({
  id: z.string(),
  noteId: z.string(),
  authorId: z.string(),
  content: z.string(),
  createdAt: z.string().datetime(),
  updatedAt: z.string().datetime(),
});

// Note History Response
export const noteHistoryResponseSchema = z.object({
  id: z.string(),
  noteId: z.string(),
  action: noteHistoryActionEnum,
  payload: z.object({
    oldStatus: z.string().optional(),
    newStatus: z.string().optional(),
    commentText: z.string().optional(),
    reason: z.string().optional(),
    changes: z.object({
      oldPriority: z.string().optional(),
      newPriority: z.string().optional(),
      titleChanged: z.boolean().optional(),
      contentChanged: z.boolean().optional(),
    }).passthrough().optional(),
  }).optional(),
  authorId: z.string(),
  createdAt: z.string().datetime(),
});

// Notes List Response
export const notesListResponseSchema = z.array(noteResponseSchema);

// Note Comments List Response
export const noteCommentsListResponseSchema = z.array(noteCommentResponseSchema);

// Note History List Response
export const noteHistoryListResponseSchema = z.array(noteHistoryResponseSchema);

// Types for frontend (exported via z.infer for type safety)
export type Note = z.infer<typeof noteResponseSchema>;
export type NoteComment = z.infer<typeof noteCommentResponseSchema>;
export type NoteHistoryEntry = z.infer<typeof noteHistoryResponseSchema>;
export type NotePriority = z.infer<typeof notePriorityEnum>;
export type NoteStatus = z.infer<typeof noteStatusEnum>;
export type NoteHistoryAction = z.infer<typeof noteHistoryActionEnum>;
export type NoteLayout = z.infer<typeof noteLayoutResponseSchema>;

// Input types (синхронизированы с бэкендом)
export interface CreateNoteInput {
  title: string;
  content: string;
  priority?: NotePriority;
  isPublic?: boolean;
  column?: number;
  positionY?: number;
  height?: number;
  reminderAt?: string | null;
  userId?: string;
}

export interface UpdateNoteInput {
  title?: string;
  content?: string;
  priority?: NotePriority;
  status?: NoteStatus;
  isPublic?: boolean;
  column?: number;
  positionY?: number;
  height?: number;
  reminderAt?: string | null;
  comment?: string;
}

export interface ChangeNoteStatusInput {
  status: NoteStatus;
  comment?: string;
  reason?: string;
}

export interface CreateNoteCommentInput {
  noteId: string;
  content: string;
}

/**
 * Note layout response schema
 */
export const noteLayoutResponseSchema = z.object({
  id: z.string(),
  noteId: z.string(),
  userId: z.string(),
  column: z.number().int().min(1).max(6),
  positionY: z.number().int().min(0),
  height: z.number().int().min(65).max(1000),
  reminderAt: z.string().datetime().nullable(),
  lastViewedAt: z.string().datetime().nullable(),
  createdAt: z.string().datetime(),
  updatedAt: z.string().datetime(),
});

/**
 * Note Repository
 */
export class NoteRepository extends BaseRepository {
  protected basePath = '/notes';

  /**
   * Получить все заметки
   */
  async getAll(): Promise<Note[]> {
    const config: RequestConfig<Note[]> = {
      schema: notesListResponseSchema,
    };

    return this.get<Note[]>('', config);
  }

  /**
   * Получить все заметки без кэша (принудительное обновление)
   */
  async getAllFresh(): Promise<Note[]> {
    const config: RequestConfig<Note[]> = {
      schema: notesListResponseSchema,
    };

    return this.getNoCache<Note[]>('', config);
  }

  /**
   * Создать новую заметку
   */
  async create(data: CreateNoteInput): Promise<Note> {
    const config: RequestConfig<Note> = {
      schema: noteResponseSchema,
    };

    return this.post<CreateNoteInput, Note>('', data, config);
  }

  /**
   * Обновить заметку
   */
  async update(id: string, data: UpdateNoteInput): Promise<Note> {
    const config: RequestConfig<Note> = {
      schema: noteResponseSchema,
    };

    console.log('[NoteRepository] update: Invalidating cache before update');
    this.invalidateCache(); // Инвалидируем кэш перед обновлением
    
    const result = this.put<UpdateNoteInput, Note>(`/${id}`, data, config);
    
    console.log('[NoteRepository] update: Cache invalidated, update sent');
    return result;
  }

  /**
   * Удалить заметку
   */
  async deleteNote(id: string): Promise<void> {
    return this.delete(`/${id}`);
  }

  /**
   * Изменить статус заметки
   */
  async changeStatus(id: string, data: ChangeNoteStatusInput): Promise<Note> {
    const config: RequestConfig<Note> = {
      schema: noteResponseSchema,
    };

    return this.post<ChangeNoteStatusInput, Note>(`/${id}/status`, data, config);
  }

  /**
   * Получить комментарии к заметке
   */
  async fetchComments(noteId: string): Promise<NoteComment[]> {
     const config: RequestConfig<NoteComment[]> = {
       schema: noteCommentsListResponseSchema,
     };

     return this.get<NoteComment[]>(`/${noteId}/comments`, config);
  }

  /**
   * Создать комментарий к заметке
   */
  async createComment(data: CreateNoteCommentInput): Promise<NoteComment> {
     const config: RequestConfig<NoteComment> = {
       schema: noteCommentResponseSchema,
     };

     return this.post<CreateNoteCommentInput, NoteComment>('/comments', data, config);
  }

  /**
   * Получить историю заметки
   */
  async fetchHistory(noteId: string): Promise<NoteHistoryEntry[]> {
     const config: RequestConfig<NoteHistoryEntry[]> = {
       schema: noteHistoryListResponseSchema,
     };

     return this.get<NoteHistoryEntry[]>(`/${noteId}/history`, config);
   }

  /**
   * Получить layout заметки для текущего пользователя
   */
  async fetchNoteLayout(userId: string): Promise<NoteLayout[]> {
     const config: RequestConfig<NoteLayout[]> = {
       schema: z.array(noteLayoutResponseSchema),
     };

     return this.get<NoteLayout[]>(`/layouts/${userId}`, config);
   }

  /**
   * Обновить layout заметки
   */
  async updateNoteLayout(noteId: string, data: Partial<NoteLayout>): Promise<NoteLayout> {
     const config: RequestConfig<NoteLayout> = {
       schema: noteLayoutResponseSchema,
     };

     return this.put<Partial<NoteLayout>, NoteLayout>(`/layouts/${noteId}`, data, config);
   }

   /**
     * Отметить заметку как просмотренную (обновляет lastViewedAt в note_layouts)
     */
    async markNoteAsViewed(noteId: string): Promise<void> {
       const config: RequestConfig<void> = {
         schema: z.void(),
       };
       return this.patch<{}, void>(`/${noteId}/view`, {}, config);
    }
}

/**
   * Синглтон экземпляр NoteRepository
 */
export const noteRepository = new NoteRepository();
