import { Component, inject, signal, OnInit, computed } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzMessageService } from 'ng-zorro-antd/message';
import { CourseService } from '../../services/course.service';
import { EnrollmentService } from '../../services/enrollment.service';
import { AuthService } from '../../services/auth.service';
import { CourseDetails, Topic, Resource, CourseProgress } from '../../models/types';
import { getErrorMessage } from '../../utils/error.utils';
import { forkJoin, of } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Component({
  selector: 'app-course-viewer',
  imports: [NzIconModule],
  providers: [NzMessageService],
  templateUrl: './course-viewer.html',
  styleUrl: './course-viewer.css'
})
export class CourseViewerPage implements OnInit {
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly courseService = inject(CourseService);
  private readonly enrollmentService = inject(EnrollmentService);
  private readonly authService = inject(AuthService);
  private readonly message = inject(NzMessageService);

  course = signal<CourseDetails | null>(null);
  progress = signal<CourseProgress | null>(null);
  loading = signal(true);
  enrolling = signal(false);
  isEnrolled = signal(false);
  expandedTopicId = signal<string | null>(null);
  completedTopicIds = signal<Set<string>>(new Set());
  completedResourceIds = signal<Set<string>>(new Set());
  expandedResourceId = signal<string | null>(null);

  get currentUser() {
    return this.authService.currentUser();
  }

  isOwnCourse = computed(() => {
    const user = this.currentUser;
    const course = this.course();
    return user && course ? course.creatorId === user.userId : false;
  });

  progressPercent = computed(() => {
    const p = this.progress();
    return p ? Math.round(p.progressPercentage) : 0;
  });

  ngOnInit(): void {
    const id = this.route.snapshot.paramMap.get('id')!;
    this.loadCourse(id);
  }

  loadCourse(id: string): void {
    this.loading.set(true);
    const user = this.currentUser;

    const course$ = this.courseService.getCourseById(id);
    const enrollments$ = user
      ? this.enrollmentService.getEnrollments(user.userId).pipe(catchError(() => of([])))
      : of([]);
    const progress$ = user
      ? this.enrollmentService.getCourseProgress(id, user.userId).pipe(catchError(() => of(null)))
      : of(null);

    forkJoin([course$, enrollments$, progress$]).subscribe({
      next: ([course, enrollments, progress]) => {
        this.course.set(course);
        this.progress.set(progress);
        if (enrollments.length > 0) {
          this.isEnrolled.set(enrollments.some((e: any) => e.courseId === id));
        }
        if (course.topics.length > 0) {
          this.expandedTopicId.set(course.topics[0].id);
        }
        this.loading.set(false);
      },
      error: () => {
        this.loading.set(false);
        this.message.error('Impossible de charger le cours');
        this.router.navigate(['/catalog']);
      }
    });
  }

  enroll(): void {
    const user = this.currentUser;
    const course = this.course();
    if (!user || !course) return;

    this.enrolling.set(true);
    this.enrollmentService.enroll(course.id, user.userId).subscribe({
      next: () => {
        this.isEnrolled.set(true);
        this.enrolling.set(false);
        this.message.success('Inscription réussie !');
        this.loadProgress(course.id, user.userId);
      },
      error: (err) => {
        this.enrolling.set(false);
        this.message.error(getErrorMessage(err, "Erreur lors de l'inscription"));
      }
    });
  }

  loadProgress(courseId: string, userId: string): void {
    this.enrollmentService.getCourseProgress(courseId, userId).subscribe({
      next: (p) => this.progress.set(p),
      error: () => {}
    });
  }

  toggleTopic(topicId: string): void {
    this.expandedTopicId.set(
      this.expandedTopicId() === topicId ? null : topicId
    );
  }

  isTopicExpanded(topicId: string): boolean {
    return this.expandedTopicId() === topicId;
  }

  isTopicDone(topicId: string): boolean {
    return this.completedTopicIds().has(topicId);
  }

  isResourceDone(resourceId: string): boolean {
    return this.completedResourceIds().has(resourceId);
  }

  markTopicDone(topic: Topic, event: Event): void {
    event.stopPropagation();
    const user = this.currentUser;
    if (!user || !this.isEnrolled()) return;

    this.enrollmentService.markTopicProgress(topic.id, user.userId, true).subscribe({
      next: () => {
        this.completedTopicIds.update(s => new Set([...s, topic.id]));
        const course = this.course();
        if (course) this.loadProgress(course.id, user.userId);
        this.message.success('Sujet marqué comme terminé');
      },
      error: () => {}
    });
  }

  openResource(resource: Resource, event: Event): void {
    event.stopPropagation();

    if (resource.type === 'Text') {
      this.expandedResourceId.set(
        this.expandedResourceId() === resource.id ? null : resource.id
      );
      return;
    }

    if (resource.content) {
      window.open(resource.content, '_blank');
    }

    if (this.isEnrolled()) {
      this.markResourceDone(resource);
    }
  }

  isResourceExpanded(resourceId: string): boolean {
    return this.expandedResourceId() === resourceId;
  }

  markResourceDone(resource: Resource): void {
    const user = this.currentUser;
    if (!user || !this.isEnrolled()) return;

    this.enrollmentService.markResourceProgress(resource.id, user.userId, true).subscribe({
      next: () => {
        this.completedResourceIds.update(s => new Set([...s, resource.id]));
        const course = this.course();
        if (course) this.loadProgress(course.id, user.userId);
      },
      error: () => {}
    });
  }

  restartCourse(): void {
    const course = this.course();
    const user = this.currentUser;
    if (!course || !user) return;

    const topicCalls = course.topics.map(t =>
      this.enrollmentService.markTopicProgress(t.id, user.userId, false)
    );
    const resourceCalls = course.topics.flatMap(t =>
      t.resources.map(r => this.enrollmentService.markResourceProgress(r.id, user.userId, false))
    );

    forkJoin([...topicCalls, ...resourceCalls]).subscribe({
      next: () => {
        this.completedTopicIds.set(new Set());
        this.completedResourceIds.set(new Set());
        this.progress.set(null);
        this.loadProgress(course.id, user.userId);
        this.message.success('Progression remise à zéro');
      },
      error: () => this.message.error('Erreur lors de la remise à zéro')
    });
  }

  editCourse(): void {
    const course = this.course();
    if (course) this.router.navigate(['/courses', course.id, 'edit']);
  }

  goBack(): void {
    this.router.navigate(['/catalog']);
  }

  getResourceIcon(type: string): string {
    switch (type) {
      case 'Video': return 'video-camera';
      case 'Text': return 'file-text';
      case 'File': return 'file';
      default: return 'link';
    }
  }
}
