import { api } from "@/lib/api-client";
import { asPaginated, asRecordData } from "@/lib/odoo-api";
import type { User } from "@/types/auth";
import type {
  Course,
  Batch,
  TimetableSession,
  AttendanceRecord,
  GradeRecord,
  CourseCreateRequest,
  PaginatedResponse,
  PaginationParams,
  ApiSuccessResponse,
  LmsStudentRecord,
  LmsTeacherRecord,
  LmsStudentCreateRequest,
  LmsTeacherCreateRequest,
  MyEnrolledCourse,
  EnrollStudentRequest,
  BulkEnrollRequest,
  LmsBranch,
  CourseSection,
} from "@/types";

function mapCourseRaw(r: Record<string, unknown>): Course {
  const status = (r.status as Course["status"]) || "draft";
  const enrolled = Number(r.student_count ?? 0);
  const maxCap = Number(r.max_capacity ?? 0);
  return {
    id: r.id as number,
    title: (r.title as string) || (r.name as string) || "",
    code: (r.code as string) || "",
    subject_id: Array.isArray(r.subject_ids) && (r.subject_ids as number[]).length ? (r.subject_ids as number[])[0] : undefined,
    subject_name: Array.isArray(r.subject_names) ? String((r.subject_names as string[])[0] || "") : "",
    encoach_subject_id: (r.encoach_subject_id as number | null) ?? null,
    encoach_subject_name: (r.encoach_subject_name as string) || "",
    topic_ids: (r.topic_ids as number[]) || [],
    topic_names: (r.topic_names as string[]) || [],
    learning_objective_ids: (r.learning_objective_ids as number[]) || [],
    learning_objective_names: (r.learning_objective_names as string[]) || [],
    tag_ids: (r.tag_ids as number[]) || [],
    tags: (r.tags as { id: number; name: string; color: string }[]) || [],
    difficulty_level: (r.difficulty_level as Course["difficulty_level"]) || "",
    cefr_level: (r.cefr_level as string) || "",
    instructor_id: 0,
    instructor_name: "",
    description: (r.description as string) || "",
    level: "Beginner",
    modules: [],
    enrolled,
    max_capacity: maxCap,
    status,
    start_date: "",
    end_date: "",
    chapter_count: Number(r.chapter_count ?? 0),
    resource_count: Number(r.resource_count ?? 0),
    objective_count: Number(r.objective_count ?? 0),
    section_count: Number(r.section_count ?? 0),
    sections: Array.isArray(r.sections)
      ? (r.sections as Record<string, unknown>[]).map(mapSectionRaw)
      : [],
    branch_id: (r.branch_id as number | null) ?? null,
    branch_name: (r.branch_name as string) || "",
  };
}

function mapBatchRaw(r: Record<string, unknown>): Batch {
  const st = String(r.status || "draft");
  const statusMap: Record<string, Batch["status"]> = {
    draft: "upcoming",
    active: "active",
    completed: "completed",
  };
  const teacherIds = (r.teacher_ids as number[]) || [];
  const teacherNames = (r.teacher_names as string[]) || [];
  return {
    id: r.id as number,
    name: String(r.name || ""),
    course_id: Number(r.course_id || 0),
    course_name: String(r.course_name || ""),
    teacher_id: teacherIds[0] || 0,
    teacher_name: teacherNames[0] || "",
    teacher_ids: teacherIds,
    teacher_names: teacherNames,
    student_ids: ((r.students as { id: number }[]) ?? []).map((s) => s.id),
    student_count: Number(r.student_count ?? 0),
    start_date: String(r.start_date || ""),
    end_date: String(r.end_date || ""),
    schedule: "",
    status: statusMap[st] || "upcoming",
    capacity: Number(r.max_students ?? 0),
    branch_id: (r.branch_id as number | null) ?? null,
    branch_name: (r.branch_name as string) || "",
    classroom_id: (r.classroom_id as number | null) ?? null,
    classroom_name: (r.classroom_name as string) || "",
    course_section_id: (r.course_section_id as number | null) ?? null,
    course_section_name: (r.course_section_name as string) || "",
    course_section_code: (r.course_section_code as string) || "",
    term_key: (r.term_key as string) || "",
  };
}

function mapSectionRaw(r: Record<string, unknown>): CourseSection {
  return {
    id: Number(r.id || 0),
    name: String(r.name || ""),
    code: String(r.code || ""),
    sequence: Number(r.sequence || 0),
    active: Boolean(r.active ?? true),
    notes: String(r.notes || ""),
    course_id: Number(r.course_id || 0),
    course_name: String(r.course_name || ""),
    entity_id: (r.entity_id as number | null) ?? null,
    entity_name: String(r.entity_name || ""),
    branch_id: (r.branch_id as number | null) ?? null,
    branch_name: String(r.branch_name || ""),
    batch_count: Number(r.batch_count || 0),
  };
}

/** Map OpenEduCat student for screens that still expect `User` (admin tables). */
export function lmsStudentToUser(s: LmsStudentRecord): User {
  const active = s.status === "active";
  return {
    id: s.id,
    name: s.name,
    email: s.email || "",
    login: s.email || "",
    user_type: "student",
    phone: s.phone || undefined,
    gender: s.gender || undefined,
    student_id: String(s.id),
    is_verified: active,
    entities:
      s.batch_id != null
        ? [{ id: s.batch_id, name: s.batch_name || "Batch" }]
        : [],
    classrooms: [],
  };
}

export function lmsTeacherToUser(t: LmsTeacherRecord): User {
  return {
    id: t.id,
    name: t.name,
    email: t.email || "",
    login: t.email || "",
    user_type: "teacher",
    phone: t.phone || undefined,
    gender: t.gender || undefined,
    is_verified: true,
    entities: t.department_id ? [{ id: t.department_id, name: t.department_name || "Department" }] : [],
    classrooms: [],
  };
}

export const lmsService = {
  async getMyEnrolledCourses(): Promise<{ items: MyEnrolledCourse[]; total: number }> {
    return api.get("/student/my-courses");
  },

  async enrollStudent(studentId: number, data: EnrollStudentRequest): Promise<{ success: boolean; enrolled_course_ids: number[] }> {
    return api.post(`/students/${studentId}/enroll`, data);
  },

  async bulkEnrollInCourse(courseId: number, data: BulkEnrollRequest): Promise<{ success: boolean; enrolled_student_ids: number[]; total_enrolled: number }> {
    return api.post(`/courses/${courseId}/enroll`, data);
  },

  async listCourses(params?: PaginationParams & { status?: string }): Promise<PaginatedResponse<Course>> {
    const raw = await api.get<unknown>("/courses", params);
    const p = asPaginated<Record<string, unknown>>(raw);
    const items = p.items.map(mapCourseRaw);
    return { items, total: p.total, page: p.page, size: p.size, pages: p.pages };
  },

  async listBranches(params?: PaginationParams & { search?: string; entity_id?: number; active?: boolean }): Promise<PaginatedResponse<LmsBranch>> {
    const raw = await api.get<unknown>("/branches", params as Record<string, string | number | boolean | undefined>);
    return asPaginated<LmsBranch>(raw);
  },

  async createBranch(data: Partial<LmsBranch>): Promise<LmsBranch> {
    const raw = await api.post<unknown>("/branches", data);
    return asRecordData<LmsBranch>(raw);
  },

  async updateBranch(id: number, data: Partial<LmsBranch>): Promise<LmsBranch> {
    const raw = await api.patch<unknown>(`/branches/${id}`, data);
    return asRecordData<LmsBranch>(raw);
  },

  async deleteBranch(id: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/branches/${id}`);
  },

  async getCourse(id: number): Promise<Course> {
    const raw = await api.get<unknown>(`/courses/${id}`);
    return mapCourseRaw(asRecordData<Record<string, unknown>>(raw));
  },

  async createCourse(data: CourseCreateRequest): Promise<Course> {
    const body: Record<string, unknown> = {
      name: data.title,
      code: data.code,
      description: data.description,
      max_capacity: data.max_capacity,
      status: "draft",
    };
    if (data.encoach_subject_id) body.encoach_subject_id = data.encoach_subject_id;
    if (data.topic_ids?.length) body.topic_ids = data.topic_ids;
    if (data.learning_objective_ids?.length) body.learning_objective_ids = data.learning_objective_ids;
    if (data.tag_ids?.length) body.tag_ids = data.tag_ids;
    if (data.difficulty_level) body.difficulty_level = data.difficulty_level;
    if (data.cefr_level) body.cefr_level = data.cefr_level;
    const raw = await api.post<unknown>("/courses", body);
    return mapCourseRaw(asRecordData<Record<string, unknown>>(raw));
  },

  async updateCourse(id: number, data: Partial<CourseCreateRequest>): Promise<Course> {
    const body: Record<string, unknown> = {};
    if (data.title != null) body.name = data.title;
    if (data.code != null) body.code = data.code;
    if (data.description != null) body.description = data.description;
    if (data.max_capacity != null) body.max_capacity = data.max_capacity;
    if (data.encoach_subject_id !== undefined) body.encoach_subject_id = data.encoach_subject_id || null;
    if (data.topic_ids !== undefined) body.topic_ids = data.topic_ids;
    if (data.learning_objective_ids !== undefined) body.learning_objective_ids = data.learning_objective_ids;
    if (data.tag_ids !== undefined) body.tag_ids = data.tag_ids;
    if (data.difficulty_level !== undefined) body.difficulty_level = data.difficulty_level;
    if (data.cefr_level !== undefined) body.cefr_level = data.cefr_level;
    const raw = await api.patch<unknown>(`/courses/${id}`, body);
    return mapCourseRaw(asRecordData<Record<string, unknown>>(raw));
  },

  async deleteCourse(id: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/courses/${id}`);
  },

  async listCourseSections(courseId: number): Promise<{ items: CourseSection[]; total: number }> {
    const raw = await api.get<unknown>(`/courses/${courseId}/sections`);
    const p = asPaginated<Record<string, unknown>>(raw);
    return { ...p, items: p.items.map(mapSectionRaw) };
  },

  async createCourseSection(
    courseId: number,
    data: { name: string; code: string; sequence?: number; active?: boolean; notes?: string; branch_id?: number | null },
  ): Promise<CourseSection> {
    const raw = await api.post<unknown>(`/courses/${courseId}/sections`, data);
    return asRecordData<CourseSection>(raw);
  },

  async updateCourseSection(
    courseId: number,
    sectionId: number,
    data: Partial<{ name: string; code: string; sequence: number; active: boolean; notes: string; branch_id: number | null }>,
  ): Promise<CourseSection> {
    const raw = await api.patch<unknown>(`/courses/${courseId}/sections/${sectionId}`, data);
    return asRecordData<CourseSection>(raw);
  },

  async deleteCourseSection(courseId: number, sectionId: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/courses/${courseId}/sections/${sectionId}`);
  },

  async generateDefaultCourseSections(
    courseId: number,
    data?: { codes?: string[]; branch_id?: number | null },
  ): Promise<{ items: CourseSection[]; created_count: number; created_ids: number[]; total: number }> {
    const raw = await api.post<{
      items: Record<string, unknown>[];
      created_count: number;
      created_ids: number[];
      total: number;
    }>(`/courses/${courseId}/sections/generate-defaults`, data ?? {});
    return {
      created_count: raw.created_count ?? 0,
      created_ids: raw.created_ids ?? [],
      total: raw.total ?? 0,
      items: (raw.items ?? []).map(mapSectionRaw),
    };
  },

  async aiGenerateCourse(data: { title: string; subject_id?: number; level?: string }): Promise<{ outline: unknown }> {
    return api.post("/courses/ai-generate", data);
  },

  async listBatches(params?: PaginationParams): Promise<PaginatedResponse<Batch>> {
    const raw = await api.get<unknown>("/batches", params);
    const p = asPaginated<Record<string, unknown>>(raw);
    const items = p.items.map(mapBatchRaw);
    return { items, total: p.total, page: p.page, size: p.size, pages: p.pages };
  },

  async getBatch(id: number): Promise<Batch> {
    const raw = await api.get<unknown>(`/batches/${id}`);
    return mapBatchRaw(asRecordData<Record<string, unknown>>(raw));
  },

  async createBatch(data: Partial<Batch>): Promise<Batch> {
    const raw = await api.post<unknown>("/batches", data);
    return mapBatchRaw(asRecordData<Record<string, unknown>>(raw));
  },

  async updateBatch(id: number, data: Partial<Batch>): Promise<Batch> {
    const raw = await api.patch<unknown>(`/batches/${id}`, data);
    return mapBatchRaw(asRecordData<Record<string, unknown>>(raw));
  },

  async deleteBatch(id: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/batches/${id}`);
  },

  async listStudents(params?: PaginationParams & { search?: string; batch_id?: number }): Promise<PaginatedResponse<LmsStudentRecord>> {
    const raw = await api.get<unknown>("/students", params as Record<string, string | number | boolean | undefined>);
    return asPaginated<LmsStudentRecord>(raw);
  },

  async getStudent(id: number): Promise<LmsStudentRecord> {
    const raw = await api.get<unknown>(`/students/${id}`);
    return asRecordData<LmsStudentRecord>(raw);
  },

  async createStudent(data: LmsStudentCreateRequest): Promise<LmsStudentRecord> {
    const raw = await api.post<unknown>("/students", data);
    return asRecordData<LmsStudentRecord>(raw);
  },

  async updateStudent(id: number, data: Partial<LmsStudentCreateRequest & { status?: string }>): Promise<LmsStudentRecord> {
    const raw = await api.patch<unknown>(`/students/${id}`, data);
    return asRecordData<LmsStudentRecord>(raw);
  },

  async listTeachers(params?: PaginationParams & { search?: string }): Promise<PaginatedResponse<LmsTeacherRecord>> {
    const raw = await api.get<unknown>("/teachers", params as Record<string, string | number | boolean | undefined>);
    return asPaginated<LmsTeacherRecord>(raw);
  },

  async createTeacher(data: LmsTeacherCreateRequest): Promise<LmsTeacherRecord> {
    const raw = await api.post<unknown>("/teachers", data);
    return asRecordData<LmsTeacherRecord>(raw);
  },

  async deleteTeacher(id: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/teachers/${id}`);
  },

  async getBatchStudents(batchId: number): Promise<{ data: { id: number; name: string; email: string; course_id: number; course_name: string }[]; total: number }> {
    return api.get(`/batches/${batchId}/students`);
  },

  async addStudentsToBatch(batchId: number, studentIds: number[]): Promise<{ success: boolean; added_ids: number[]; total: number }> {
    return api.post(`/batches/${batchId}/students`, { student_ids: studentIds });
  },

  async removeStudentsFromBatch(batchId: number, studentIds: number[]): Promise<{ success: boolean; removed_ids: number[]; total: number }> {
    return api.post(`/batches/${batchId}/students/remove`, { student_ids: studentIds });
  },

  async getBatchTeachers(batchId: number): Promise<{ items: { id: number; name: string; email: string }[]; total: number }> {
    return api.get(`/batches/${batchId}/teachers`);
  },

  async setBatchTeachers(
    batchId: number,
    teacherIds: number[],
    mode: "set" | "add" = "set",
  ): Promise<{ success: boolean; teacher_ids: number[] }> {
    return api.post(`/batches/${batchId}/teachers`, { teacher_ids: teacherIds, mode });
  },

  async removeBatchTeachers(
    batchId: number,
    teacherIds: number[],
  ): Promise<{ success: boolean; teacher_ids: number[] }> {
    return api.post(`/batches/${batchId}/teachers/remove`, { teacher_ids: teacherIds });
  },

  async deleteStudent(id: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/students/${id}`);
  },

  async getTimetable(params?: { course_id?: number; teacher_id?: number; batch_id?: number }): Promise<TimetableSession[]> {
    const raw = await api.get<{ data: TimetableSession[] } | TimetableSession[]>("/timetable", params as Record<string, string | number | boolean | undefined>);
    return Array.isArray(raw) ? raw : (raw as { data: TimetableSession[] }).data ?? [];
  },

  async createTimetableSession(data: Partial<TimetableSession>): Promise<TimetableSession> {
    return api.post<TimetableSession>("/timetable", data);
  },

  async deleteTimetableSession(id: number): Promise<ApiSuccessResponse> {
    return api.delete<ApiSuccessResponse>(`/timetable/${id}`);
  },

  async getAttendance(params?: { course_id?: number; student_id?: number; date?: string }): Promise<AttendanceRecord[]> {
    const raw = await api.get<{ data: AttendanceRecord[] } | AttendanceRecord[]>("/attendance", params as Record<string, string | number | boolean | undefined>);
    return Array.isArray(raw) ? raw : (raw as { data: AttendanceRecord[] }).data ?? [];
  },

  async recordAttendance(data: { course_id: number; date: string; records: { student_id: number; status: string }[] }): Promise<ApiSuccessResponse> {
    return api.post<ApiSuccessResponse>("/attendance", data);
  },

  async getGrades(params?: { course_id?: number; student_id?: number }): Promise<GradeRecord[]> {
    const raw = await api.get<{ data: GradeRecord[] } | GradeRecord[]>("/grades", params as Record<string, string | number | boolean | undefined>);
    return Array.isArray(raw) ? raw : (raw as { data: GradeRecord[] }).data ?? [];
  },

  async getCourseTaxonomy(courseId: number): Promise<{
    subject: { id: number; name: string; code: string } | null;
    domains: { id: number; name: string }[];
    topics: { id: number; name: string; domain_id: number; domain_name: string }[];
    objectives: { id: number; name: string; topic_id: number; topic_name: string; bloom_level: string }[];
    tags: { id: number; name: string; color: string }[];
  }> {
    return api.get(`/courses/${courseId}/taxonomy`);
  },

  async getSubjectCourses(subjectId: number): Promise<{ items: Course[]; total: number }> {
    const raw = await api.get<unknown>(`/subjects/${subjectId}/courses`);
    const p = asPaginated<Record<string, unknown>>(raw);
    return { ...p, items: p.items.map(mapCourseRaw) };
  },

  async listLearningObjectives(params?: { topic_id?: number; topic_ids?: string; subject_id?: number }): Promise<{
    items: { id: number; name: string; description: string; topic_id: number; topic_name: string; bloom_level: string; cefr_level: string }[];
    total: number;
  }> {
    return api.get("/learning-objectives", params as Record<string, string | number | boolean | undefined>);
  },

  async listDomains(params?: { subject_id?: number }): Promise<{
    items: { id: number; name: string; subject_id: number; subject_name: string; description: string }[];
    total: number;
  }> {
    return api.get("/domains", params as Record<string, string | number | boolean | undefined>);
  },
};
