/**
 * @copyright 2026 NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */

import { Component, OnInit, inject, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterLink } from '@angular/router';
import { MusicService } from '../../services/music.service';
import { AuthService } from '../../services/auth.service';
import { CommentsService } from '../../services/comments.service';
import { SanitizeService } from '../../services/sanitize.service';
import { SuggestionService } from '../../services/suggestion.service';
import { PaginationComponent } from '../shared/pagination.component';
import { LikeButtonComponent } from '../shared/like-button.component';
import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment, SuggestionEntity, Link } from '@library/shared-types';

@Component({
  selector: 'app-music-list',
  standalone: true,
  imports: [CommonModule, FormsModule, RouterLink, PaginationComponent, LikeButtonComponent],
  template: `
    <div class="container">
      <div class="page-hero">
        <img src="/assets/avatars/music-avatar.jpg" alt="Music avatar" class="page-avatar" />
      </div>

      <div class="header-section">
        <h2>My Music Collection</h2>
        @if (authService.isAdmin()) {
          <button (click)="toggleAddForm()" class="btn btn-primary">
            {{ showAddForm() ? 'Cancel' : 'Add Music' }}
          </button>
        } @else if (authService.isAuthenticated() && !authService.user()?.isBanned) {
          <button (click)="toggleSuggestForm()" class="btn btn-primary">
            {{ showSuggestForm() ? 'Cancel' : 'Suggest Music' }}
          </button>
        }
      </div>

      @if (showAddForm() && authService.isAdmin()) {
        <form (ngSubmit)="addMusic()" class="add-form">
          <h3>Add New Music</h3>
          <div class="form-group">
            <label for="title">Title</label>
            <input
              type="text"
              id="title"
              [(ngModel)]="newMusic.title"
              name="title"
              required
              placeholder="Album/Single/EP title"
            >
          </div>

          <div class="form-group">
            <label for="artist">Artist</label>
            <input
              type="text"
              id="artist"
              [(ngModel)]="newMusic.artist"
              name="artist"
              required
              placeholder="Artist name"
            >
          </div>

          <div class="form-group">
            <label for="type">Type</label>
            <select id="type" [(ngModel)]="newMusic.type" name="type" required>
              <option [value]="MusicType.album">Album</option>
              <option [value]="MusicType.single">Single</option>
              <option [value]="MusicType.ep">EP</option>
            </select>
          </div>

          <div class="form-group">
            <label for="status">Status</label>
            <select id="status" [(ngModel)]="newMusic.status" name="status" required>
              <option [value]="MusicStatus.listening">Currently Listening</option>
              <option [value]="MusicStatus.completed">Completed</option>
              <option [value]="MusicStatus.wantToListen">Want to Listen</option>
              <option [value]="MusicStatus.retired">Retired</option>
            </select>
          </div>

          <div class="form-group">
            <label for="dateStarted">Date Started</label>
            <input
              type="date"
              id="dateStarted"
              [(ngModel)]="newMusic.dateStarted"
              name="dateStarted"
            >
          </div>

          <div class="form-group">
            <label for="dateFinished">Date Finished</label>
            <input
              type="date"
              id="dateFinished"
              [(ngModel)]="newMusic.dateFinished"
              name="dateFinished"
            >
          </div>

          <div class="form-group">
            <label for="rating">Rating (1-10)</label>
            <input
              type="number"
              id="rating"
              [(ngModel)]="newMusic.rating"
              name="rating"
              min="1"
              max="10"
            >
          </div>

          <div class="form-row">
            <div class="form-group">
              <label for="timeHours">Time Spent (Hours)</label>
              <input
                type="number"
                id="timeHours"
                [(ngModel)]="newMusicTimeHours"
                name="timeHours"
                min="0"
                placeholder="0"
                (ngModelChange)="updateNewMusicTimeSpent()"
              >
            </div>
            <div class="form-group">
              <label for="timeMinutes">Time Spent (Minutes)</label>
              <input
                type="number"
                id="timeMinutes"
                [(ngModel)]="newMusicTimeMinutes"
                name="timeMinutes"
                min="0"
                max="59"
                placeholder="0"
                (ngModelChange)="updateNewMusicTimeSpent()"
              >
            </div>
          </div>

          <div class="form-group">
            <label for="notes">Notes</label>
            <textarea
              id="notes"
              [(ngModel)]="newMusic.notes"
              name="notes"
              rows="3"
              placeholder="Your thoughts about this music..."
            ></textarea>
          </div>

          <div class="form-group">
            <label for="coverArt">Album Art (max 500KB)</label>
            <input
              type="file"
              id="coverArt"
              name="coverArt"
              accept="image/*"
              (change)="onImageSelected($event, 'new')"
            >
            @if (newMusicImagePreview()) {
              <div class="image-preview">
                <img [src]="newMusicImagePreview()" alt="Album art preview">
                <button type="button" (click)="clearImage('new')" class="btn btn-danger btn-sm">Remove</button>
              </div>
            }
            @if (imageError()) {
              <span class="error-text">{{ imageError() }}</span>
            }
          </div>

          <div class="form-group">
            <div class="tags-input-container" aria-label="Tags">
              @for (tag of newMusic.tags; track tag; let i = $index) {
                <span class="tag">
                  {{ tag }}
                  <button type="button" (click)="removeTag(i, 'new')" class="tag-remove">×</button>
                </span>
              }
              <input
                type="text"
                [(ngModel)]="newTagInput"
                name="newTagInput"
                placeholder="Add a tag and press Enter"
                (keydown.enter)="addTag('new'); $event.preventDefault()"
              >
            </div>
          </div>

          <div class="form-group" aria-label="External Links">
            <div class="links-list">
              @for (link of newMusic.links; track link.url; let i = $index) {
                <div class="link-item">
                  <span>{{ link.title }}: {{ link.url }}</span>
                  <button type="button" (click)="removeLink(i, 'new')" class="btn btn-danger btn-sm">×</button>
                </div>
              }
            </div>
            <div class="link-add-form">
              <input
                type="text"
                [(ngModel)]="newLinkTitle"
                name="newLinkTitle"
                placeholder="Link title (e.g., Spotify)"
              >
              <input
                type="url"
                [(ngModel)]="newLinkUrl"
                name="newLinkUrl"
                placeholder="https://..."
              >
              <button type="button" (click)="addLink('new')" class="btn btn-secondary btn-sm">Add Link</button>
            </div>
          </div>

          <div class="form-actions">
            <button type="submit" class="btn btn-primary">Add Music</button>
            <button type="button" (click)="toggleAddForm()" class="btn btn-secondary">Cancel</button>
          </div>
        </form>
      }

      @if (editingMusic() && authService.isAdmin()) {
        <form (ngSubmit)="saveEdit()" class="add-form">
          <h3>Edit Music</h3>
          <div class="form-group">
            <label for="edit-title">Title</label>
            <input
              type="text"
              id="edit-title"
              [(ngModel)]="editMusicData.title"
              name="title"
              required
              placeholder="Album/Single/EP title"
            >
          </div>

          <div class="form-group">
            <label for="edit-artist">Artist</label>
            <input
              type="text"
              id="edit-artist"
              [(ngModel)]="editMusicData.artist"
              name="artist"
              required
              placeholder="Artist name"
            >
          </div>

          <div class="form-group">
            <label for="edit-type">Type</label>
            <select id="edit-type" [(ngModel)]="editMusicData.type" name="type" required>
              <option [value]="MusicType.album">Album</option>
              <option [value]="MusicType.single">Single</option>
              <option [value]="MusicType.ep">EP</option>
            </select>
          </div>

          <div class="form-group">
            <label for="edit-status">Status</label>
            <select id="edit-status" [(ngModel)]="editMusicData.status" name="status" required>
              <option [value]="MusicStatus.listening">Currently Listening</option>
              <option [value]="MusicStatus.completed">Completed</option>
              <option [value]="MusicStatus.wantToListen">Want to Listen</option>
              <option [value]="MusicStatus.retired">Retired</option>
            </select>
          </div>

          <div class="form-group">
            <label for="edit-dateStarted">Date Started</label>
            <input
              type="date"
              id="edit-dateStarted"
              [(ngModel)]="editMusicData.dateStarted"
              name="dateStarted"
            >
          </div>

          <div class="form-group">
            <label for="edit-dateFinished">Date Finished</label>
            <input
              type="date"
              id="edit-dateFinished"
              [(ngModel)]="editMusicData.dateFinished"
              name="dateFinished"
            >
          </div>

          <div class="form-group">
            <label for="edit-rating">Rating (1-10)</label>
            <input
              type="number"
              id="edit-rating"
              [(ngModel)]="editMusicData.rating"
              name="rating"
              min="1"
              max="10"
            >
          </div>

          <div class="form-row">
            <div class="form-group">
              <label for="edit-timeHours">Time Spent (Hours)</label>
              <input
                type="number"
                id="edit-timeHours"
                [(ngModel)]="editMusicTimeHours"
                name="timeHours"
                min="0"
                placeholder="0"
                (ngModelChange)="updateEditMusicTimeSpent()"
              >
            </div>
            <div class="form-group">
              <label for="edit-timeMinutes">Time Spent (Minutes)</label>
              <input
                type="number"
                id="edit-timeMinutes"
                [(ngModel)]="editMusicTimeMinutes"
                name="timeMinutes"
                min="0"
                max="59"
                placeholder="0"
                (ngModelChange)="updateEditMusicTimeSpent()"
              >
            </div>
          </div>

          <div class="form-group">
            <label for="edit-notes">Notes</label>
            <textarea
              id="edit-notes"
              [(ngModel)]="editMusicData.notes"
              name="notes"
              rows="3"
              placeholder="Your thoughts about this music..."
            ></textarea>
          </div>

          <div class="form-group">
            <label for="edit-coverArt">Album Art (max 500KB)</label>
            <input
              type="file"
              id="edit-coverArt"
              name="coverArt"
              accept="image/*"
              (change)="onImageSelected($event, 'edit')"
            >
            @if (editMusicImagePreview()) {
              <div class="image-preview">
                <img [src]="editMusicImagePreview()" alt="Album art preview">
                <button type="button" (click)="clearImage('edit')" class="btn btn-danger btn-sm">Remove</button>
              </div>
            }
            @if (imageError()) {
              <span class="error-text">{{ imageError() }}</span>
            }
          </div>

          <div class="form-group">
            <div class="tags-input-container" aria-label="Tags">
              @for (tag of editMusicData.tags; track tag; let i = $index) {
                <span class="tag">
                  {{ tag }}
                  <button type="button" (click)="removeTag(i, 'edit')" class="tag-remove">×</button>
                </span>
              }
              <input
                type="text"
                [(ngModel)]="editTagInput"
                name="editTagInput"
                placeholder="Add a tag and press Enter"
                (keydown.enter)="addTag('edit'); $event.preventDefault()"
              >
            </div>
          </div>

          <div class="form-group" aria-label="External Links">
            <div class="links-list">
              @for (link of editMusicData.links; track link.url; let i = $index) {
                <div class="link-item">
                  <span>{{ link.title }}: {{ link.url }}</span>
                  <button type="button" (click)="removeLink(i, 'edit')" class="btn btn-danger btn-sm">×</button>
                </div>
              }
            </div>
            <div class="link-add-form">
              <input
                type="text"
                [(ngModel)]="editLinkTitle"
                name="editLinkTitle"
                placeholder="Link title (e.g., Spotify)"
              >
              <input
                type="url"
                [(ngModel)]="editLinkUrl"
                name="editLinkUrl"
                placeholder="https://..."
              >
              <button type="button" (click)="addLink('edit')" class="btn btn-secondary btn-sm">Add Link</button>
            </div>
          </div>

          <div class="form-actions">
            <button type="submit" class="btn btn-primary">Save Changes</button>
            <button type="button" (click)="cancelEdit()" class="btn btn-secondary">Cancel</button>
          </div>
        </form>
      }

      @if (showSuggestForm() && !authService.isAdmin() && authService.isAuthenticated()) {
        <form (ngSubmit)="submitSuggestion()" class="add-form suggest-form">
          <h3>Suggest Music</h3>
          <p class="suggest-note">Your suggestion will be reviewed by Naomi. If accepted, it will be added to the listening list!</p>
          <div class="form-group">
            <label for="suggest-title">Title</label>
            <input
              type="text"
              id="suggest-title"
              [(ngModel)]="suggestedMusic.title"
              name="title"
              required
              placeholder="Album/Single/EP title"
            >
          </div>

          <div class="form-group">
            <label for="suggest-artist">Artist</label>
            <input
              type="text"
              id="suggest-artist"
              [(ngModel)]="suggestedMusic.artist"
              name="artist"
              required
              placeholder="Artist name"
            >
          </div>

          <div class="form-group">
            <label for="suggest-type">Type</label>
            <select id="suggest-type" [(ngModel)]="suggestedMusic.type" name="type" required>
              <option [value]="MusicType.album">Album</option>
              <option [value]="MusicType.single">Single</option>
              <option [value]="MusicType.ep">EP</option>
            </select>
          </div>

          <div class="form-group">
            <label for="suggest-notes">Notes (why should Naomi listen to this?)</label>
            <textarea
              id="suggest-notes"
              [(ngModel)]="suggestedMusic.notes"
              name="notes"
              rows="3"
              placeholder="Tell Naomi why this music is worth listening to..."
            ></textarea>
          </div>

          <div class="form-group">
            <label for="suggest-coverArt">Album Art (max 500KB)</label>
            <input
              type="file"
              id="suggest-coverArt"
              name="coverArt"
              accept="image/*"
              (change)="onImageSelected($event, 'suggest')"
            >
            @if (suggestMusicImagePreview()) {
              <div class="image-preview">
                <img [src]="suggestMusicImagePreview()" alt="Album art preview">
                <button type="button" (click)="clearImage('suggest')" class="btn btn-danger btn-sm">Remove</button>
              </div>
            }
            @if (imageError()) {
              <span class="error-text">{{ imageError() }}</span>
            }
          </div>

          <div class="form-actions">
            <button type="submit" class="btn btn-primary">Submit Suggestion</button>
            <button type="button" (click)="toggleSuggestForm()" class="btn btn-secondary">Cancel</button>
          </div>
        </form>
      }

      <div class="search-section">
        <input
          type="text"
          [value]="searchQuery()"
          (input)="searchQuery.set($any($event.target).value); currentPage.set(1)"
          name="search"
          placeholder="Search by title, artist, type, or notes..."
          class="search-input"
        >
        <button (click)="toggleFilters()" class="btn btn-secondary btn-sm">
          {{ showFilters() ? 'Hide' : 'Show' }} Advanced Filters
          @if (selectedTags().length > 0) {
            ({{ selectedTags().length }})
          }
        </button>
        @if (searchQuery() || selectedTags().length > 0) {
          <button (click)="clearFilters()" class="btn btn-secondary btn-sm">
            Clear All Filters
          </button>
        }
      </div>

      @if (showFilters()) {
        <div class="advanced-filters">
          <div class="filter-group">
            <h4>Filter by Tags</h4>
            <div class="tags-filter">
              @for (tag of allTags(); track tag) {
                <label class="tag-checkbox">
                  <input
                    type="checkbox"
                    [checked]="selectedTags().includes(tag)"
                    (change)="toggleTag(tag)"
                  >
                  <span>{{ tag }}</span>
                </label>
              }
              @empty {
                <p class="no-tags">No tags available</p>
              }
            </div>
          </div>
        </div>
      }

      <div class="filters">
        <div class="filter-group">
          <strong>Type:</strong>
          <button
            (click)="setTypeFilter('all')"
            [class.active]="typeFilter() === 'all'"
            class="filter-btn"
          >
            All
          </button>
          <button
            (click)="setTypeFilter(MusicType.album)"
            [class.active]="typeFilter() === MusicType.album"
            class="filter-btn"
          >
            Albums ({{ albumCount() }})
          </button>
          <button
            (click)="setTypeFilter(MusicType.single)"
            [class.active]="typeFilter() === MusicType.single"
            class="filter-btn"
          >
            Singles ({{ singleCount() }})
          </button>
          <button
            (click)="setTypeFilter(MusicType.ep)"
            [class.active]="typeFilter() === MusicType.ep"
            class="filter-btn"
          >
            EPs ({{ epCount() }})
          </button>
        </div>

        <div class="filter-group">
          <strong>Status:</strong>
          <button
            (click)="setStatusFilter('all')"
            [class.active]="statusFilter() === 'all'"
            class="filter-btn"
          >
            All
          </button>
          <button
            (click)="setStatusFilter(MusicStatus.listening)"
            [class.active]="statusFilter() === MusicStatus.listening"
            class="filter-btn"
          >
            Listening ({{ listeningCount() }})
          </button>
          <button
            (click)="setStatusFilter(MusicStatus.completed)"
            [class.active]="statusFilter() === MusicStatus.completed"
            class="filter-btn"
          >
            Completed ({{ completedCount() }})
          </button>
          <button
            (click)="setStatusFilter(MusicStatus.wantToListen)"
            [class.active]="statusFilter() === MusicStatus.wantToListen"
            class="filter-btn"
          >
            Want to Listen ({{ wantToListenCount() }})
          </button>
          <button
            (click)="setStatusFilter(MusicStatus.retired)"
            [class.active]="statusFilter() === MusicStatus.retired"
            class="filter-btn"
          >
            Retired ({{ retiredCount() }})
          </button>
        </div>
      </div>

      @if (loading()) {
        <div class="loading">Loading music...</div>
      } @else if (filteredMusic().length === 0) {
        <div class="empty-state">
          <p>No music found with these filters.</p>
        </div>
      } @else {
        <app-pagination
          [currentPage]="currentPage()"
          [pageSize]="pageSize()"
          [totalItems]="totalFilteredMusic()"
          (pageChange)="onPageChange($event)"
          (pageSizeChange)="onPageSizeChange($event)"
        ></app-pagination>

        <div class="music-grid">
          @for (music of paginatedMusic(); track music.id) {
            <div class="music-card" [class.completed]="music.status === MusicStatus.completed">
              <a [routerLink]="['/music', music.id]" class="card-link">
                <img [src]="music.coverArt || '/assets/default-cover.jpg'" [alt]="music.title" class="music-cover">

                <div class="music-info">
                  <h3>{{ music.title }}</h3>
                  <p class="artist">{{ music.artist }}</p>

                  @if (music.type) {
                    <div class="badges">
                      <span class="type-badge type-{{ music.type }}">
                        {{ getTypeLabel(music.type) }}
                      </span>
                      <span class="status status-{{ music.status }}">
                        {{ getStatusLabel(music.status) }}
                      </span>
                    </div>
                  }

                  @if (music.rating) {
                    <div class="rating">
                      @for (star of [1,2,3,4,5,6,7,8,9,10]; track star) {
                        <span [class.filled]="star <= music.rating!">★</span>
                      }
                    </div>
                  }
                </div>
              </a>

              <div class="card-actions">
                <app-like-button
                  entityType="music"
                  [entityId]="music.id"
                ></app-like-button>

                @if (authService.isAdmin()) {
                  <div class="admin-actions">
                    <button (click)="startEdit(music)" class="btn btn-secondary btn-sm">
                      Edit
                    </button>
                    <button (click)="deleteMusic(music)" class="btn btn-danger btn-sm">
                      Delete
                    </button>
                  </div>
                }
              </div>
            </div>
          }
        </div>

        <app-pagination
          [currentPage]="currentPage()"
          [pageSize]="pageSize()"
          [totalItems]="totalFilteredMusic()"
          (pageChange)="onPageChange($event)"
          (pageSizeChange)="onPageSizeChange($event)"
        ></app-pagination>
      }
    </div>
  `,
  styles: [`
    .container {
      max-width: 1200px;
      margin: 0 auto;
      padding: 2rem;
    }

    .page-hero {
      text-align: center;
      margin-bottom: 2rem;
    }

    .page-avatar {
      width: 120px;
      height: 120px;
      border-radius: 50%;
      object-fit: cover;
      border: 3px solid #74b9ff;
      box-shadow: 0 4px 12px rgba(116, 185, 255, 0.3);
      transition: all 0.3s;
    }

    .page-avatar:hover {
      transform: scale(1.05);
      box-shadow: 0 8px 16px rgba(116, 185, 255, 0.5);
    }

    .header-section {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 2rem;
    }

    h2 {
      margin: 0;
    }

    .add-form {
      background: rgba(255, 255, 255, 0.95);
      padding: 1.5rem;
      border-radius: 8px;
      margin-bottom: 2rem;
      border: 2px solid var(--witch-lavender);
      backdrop-filter: blur(10px);
    }

    .suggest-form {
      border: 2px solid #74b9ff;
      background: #f5faff;
    }

    .suggest-note {
      color: #666;
      font-size: 0.9rem;
      margin-bottom: 1rem;
      font-style: italic;
    }

    .form-group {
      margin-bottom: 1rem;
    }

    .form-group label {
      display: block;
      margin-bottom: 0.5rem;
      font-weight: 500;
    }

    .form-group input,
    .form-group select,
    .form-group textarea {
      width: 100%;
      padding: 0.5rem;
      border: 2px solid var(--witch-lavender);
      border-radius: 4px;
      font-size: 1rem;
      background-color: var(--witch-moon);
      color: var(--witch-purple);
      transition: border-color 0.3s;
    }

    .form-group input:focus,
    .form-group select:focus,
    .form-group textarea:focus {
      outline: none;
      border-color: var(--witch-rose);
      box-shadow: 0 0 0 3px rgba(168, 87, 126, 0.2);
    }

    .form-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 1rem;
      margin-bottom: 1rem;
    }

    .form-actions {
      display: flex;
      gap: 1rem;
      margin-top: 1rem;
    }

    .search-section {
      display: flex;
      gap: 1rem;
      align-items: center;
      margin-bottom: 1rem;
      flex-wrap: wrap;
    }

    .search-input {
      flex: 1;
      min-width: 250px;
      padding: 0.5rem 1rem;
      border: 1px solid #ddd;
      border-radius: 4px;
      font-size: 1rem;
    }

    .search-input:focus {
      outline: none;
      border-color: #8b5cf6;
    }

    .advanced-filters {
      background: #f8f9fa;
      padding: 1rem;
      border-radius: 8px;
      margin-bottom: 1rem;
    }

    .filter-group h4 {
      margin: 0 0 0.75rem 0;
      color: #374151;
      font-size: 0.95rem;
      font-weight: 600;
    }

    .tags-filter {
      display: flex;
      flex-wrap: wrap;
      gap: 0.75rem;
    }

    .tag-checkbox {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      cursor: pointer;
      padding: 0.25rem 0.75rem;
      border: 1px solid #e5e7eb;
      border-radius: 20px;
      background: white;
      transition: all 0.2s;
    }

    .tag-checkbox:hover {
      border-color: #8b5cf6;
      background: #f3e8ff;
    }

    .tag-checkbox input[type="checkbox"] {
      width: 16px;
      height: 16px;
      cursor: pointer;
    }

    .tag-checkbox span {
      font-size: 0.875rem;
      color: #374151;
    }

    .no-tags {
      color: #6b7280;
      font-style: italic;
      font-size: 0.875rem;
    }

    .filters {
      display: flex;
      flex-direction: column;
      gap: 1rem;
      margin-bottom: 2rem;
    }

    .filter-group {
      display: flex;
      align-items: center;
      gap: 1rem;
      flex-wrap: wrap;
    }

    .filter-group strong {
      min-width: 60px;
      color: var(--witch-plum);
    }

    .filter-btn {
      padding: 0.5rem 1rem;
      background: var(--witch-lavender);
      color: var(--witch-purple);
      border: none;
      border-radius: 4px;
      cursor: pointer;
      transition: all 0.3s;
    }

    .filter-btn:hover {
      background: var(--witch-mauve);
      transform: translateY(-2px);
      box-shadow: 0 4px 8px var(--witch-shadow);
    }

    .filter-btn.active {
      background: #74b9ff;
      color: white;
    }

    .loading {
      text-align: center;
      padding: 2rem;
      color: var(--witch-plum);
    }

    .empty-state {
      text-align: center;
      padding: 3rem;
      color: var(--witch-plum);
    }

    .music-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: 1.5rem;
    }

    .music-card {
      background: rgba(255, 255, 255, 0.95);
      border: 2px solid var(--witch-lavender);
      border-radius: 8px;
      overflow: hidden;
      transition: all 0.3s;
      backdrop-filter: blur(10px);
      display: flex;
      flex-direction: column;
    }

    .music-card:hover {
      transform: translateY(-2px);
      box-shadow: 0 4px 12px var(--witch-shadow);
      border-color: var(--witch-mauve);
    }

    .music-card.completed {
      opacity: 0.9;
      border-color: var(--witch-mauve);
    }

    .card-link {
      text-decoration: none;
      color: inherit;
      display: block;
      flex: 1;
    }

    .card-link:hover h3 {
      color: var(--witch-rose);
    }

    .music-cover {
      width: 100%;
      height: 250px;
      object-fit: cover;
    }

    .music-cover.placeholder {
      display: flex;
      align-items: center;
      justify-content: center;
      background: var(--witch-lavender);
      font-size: 4rem;
    }

    .music-info {
      padding: 1rem;
    }

    .music-info h3 {
      margin: 0 0 0.5rem 0;
      font-size: 1.1rem;
      transition: color 0.3s;
    }

    .artist {
      color: var(--witch-plum);
      font-weight: 500;
      margin: 0.5rem 0;
    }

    .badges {
      display: flex;
      gap: 0.5rem;
      margin: 0.75rem 0;
    }

    .card-actions {
      padding: 1rem;
      border-top: 1px solid var(--witch-lavender);
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
    }

    .admin-actions {
      display: flex;
      gap: 0.5rem;
    }

    .type-badge {
      display: inline-block;
      padding: 0.25rem 0.5rem;
      border-radius: 4px;
      font-size: 0.8rem;
      font-weight: 500;
    }

    .type-album {
      background: var(--witch-purple);
      color: var(--witch-moon);
    }
    .type-single {
      background: var(--witch-rose);
      color: var(--witch-moon);
    }
    .type-ep {
      background: var(--witch-plum);
      color: var(--witch-moon);
    }

    .status {
      display: inline-block;
      padding: 0.25rem 0.5rem;
      border-radius: 4px;
      font-size: 0.8rem;
      font-weight: 500;
    }

    .status-listening {
      background: var(--witch-rose);
      color: var(--witch-moon);
    }
    .status-completed {
      background: var(--witch-mauve);
      color: var(--witch-purple);
    }
    .status-wantToListen {
      background: var(--witch-lavender);
      color: var(--witch-purple);
    }

    .rating {
      margin: 0.5rem 0;
    }

    .rating span {
      color: var(--witch-lavender);
      font-size: 1.2rem;
    }

    .rating span.filled {
      color: var(--witch-rose);
    }

    .btn {
      padding: 0.5rem 1rem;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 0.9rem;
      transition: opacity 0.3s;
    }

    .btn:hover {
      opacity: 0.8;
    }

    .btn-primary {
      background: #74b9ff;
      color: white;
    }

    .btn-primary:hover {
      background: #4a9ff5;
      transform: translateY(-2px);
      box-shadow: 0 4px 8px var(--witch-shadow);
    }

    .btn-secondary {
      background: #6b7280;
      color: white;
    }

    .btn-secondary:hover {
      background: #4b5563;
      color: white;
    }

    .btn-danger {
      background: #ef4444;
      color: white;
    }

    .btn-danger:hover {
      background: #dc2626;
    }

    .btn-sm {
      padding: 0.25rem 0.75rem;
      font-size: 0.85rem;
    }

    .btn-xs { padding: 0.15rem 0.5rem; font-size: 0.75rem; }

    .image-preview {
      margin-top: 0.5rem;
      display: flex;
      align-items: center;
      gap: 1rem;
    }

    .image-preview img {
      max-width: 100px;
      max-height: 100px;
      border-radius: 4px;
      border: 2px solid var(--witch-lavender);
    }

    .error-text {
      color: var(--witch-rose);
      font-size: 0.875rem;
      display: block;
      margin-top: 0.25rem;
    }

    input[type="file"] {
      padding: 0.5rem;
      border: 2px dashed var(--witch-lavender);
      border-radius: 4px;
      background: var(--witch-moon);
      cursor: pointer;
    }

    input[type="file"]:hover {
      border-color: var(--witch-rose);
    }

    .tags-input-container {
      display: flex;
      flex-wrap: wrap;
      gap: 0.5rem;
      padding: 0.5rem;
      border: 2px solid var(--witch-lavender);
      border-radius: 4px;
      background: var(--witch-moon);
    }

    .tags-input-container input {
      flex: 1;
      min-width: 150px;
      border: none;
      padding: 0.25rem;
      font-size: 0.9rem;
      background: transparent;
    }

    .tags-input-container input:focus {
      outline: none;
    }

    .tag {
      display: inline-flex;
      align-items: center;
      gap: 0.25rem;
      background: #74b9ff;
      color: white;
      padding: 0.25rem 0.5rem;
      border-radius: 4px;
      font-size: 0.85rem;
    }

    .tag-remove {
      background: none;
      border: none;
      color: white;
      cursor: pointer;
      padding: 0;
      font-size: 1rem;
      line-height: 1;
    }

    .tag-remove:hover {
      opacity: 0.8;
    }

    .links-list {
      margin-bottom: 0.5rem;
    }

    .link-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0.5rem;
      background: var(--witch-moon);
      border-radius: 4px;
      margin-bottom: 0.25rem;
    }

    .link-add-form {
      display: flex;
      gap: 0.5rem;
      flex-wrap: wrap;
    }

    .link-add-form input {
      flex: 1;
      min-width: 120px;
    }
  `]
})
export class MusicListComponent implements OnInit {
  musicService = inject(MusicService);
  authService = inject(AuthService);
  commentsService = inject(CommentsService);
  sanitizeService = inject(SanitizeService);
  suggestionService = inject(SuggestionService);

  music = signal<Music[]>([]);
  loading = signal(true);
  showAddForm = signal(false);
  editingMusic = signal<Music | null>(null);
  typeFilter = signal<'all' | MusicType>('all');
  statusFilter = signal<'all' | MusicStatus>('all');

  // Pagination state
  currentPage = signal(1);
  pageSize = signal(25);

  // Search and filter state
  searchQuery = signal('');
  selectedTags = signal<string[]>([]);
  showFilters = signal(false);

  // Comments state
  comments = signal<Record<string, Comment[]>>({});
  commentsLoading = signal<Record<string, boolean>>({});
  expandedComments = signal<Record<string, boolean>>({});
  newCommentContent: Record<string, string> = {};
  editingCommentId = signal<string | null>(null);
  editCommentContent = '';

  // Image upload state
  newMusicImagePreview = signal<string | null>(null);
  editMusicImagePreview = signal<string | null>(null);
  suggestMusicImagePreview = signal<string | null>(null);
  imageError = signal<string | null>(null);
  private readonly MAX_IMAGE_SIZE = 500 * 1024; // 500KB

  // Suggestion state
  showSuggestForm = signal(false);
  suggestedMusic: { title: string; artist: string; type: MusicType; notes?: string; coverArt?: string } = {
    title: '',
    artist: '',
    type: MusicType.album,
    notes: '',
    coverArt: undefined
  };

  // Expose enums to template
  MusicType = MusicType;
  MusicStatus = MusicStatus;

  // Computed signals for reactive count updates (type)
  albumCount = computed(() => this.music().filter(m => m.type === MusicType.album).length);
  singleCount = computed(() => this.music().filter(m => m.type === MusicType.single).length);
  epCount = computed(() => this.music().filter(m => m.type === MusicType.ep).length);

  // Computed signals for reactive count updates (status)
  listeningCount = computed(() => this.music().filter(m => m.status === MusicStatus.listening).length);
  completedCount = computed(() => this.music().filter(m => m.status === MusicStatus.completed).length);
  wantToListenCount = computed(() => this.music().filter(m => m.status === MusicStatus.wantToListen).length);
  retiredCount = computed(() => this.music().filter(m => m.status === MusicStatus.retired).length);

  allTags = computed(() => {
    const tagsSet = new Set<string>();
    this.music().forEach(music => {
      music.tags?.forEach(tag => tagsSet.add(tag));
    });
    return Array.from(tagsSet).sort();
  });

  filteredMusic = computed(() => {
    let filtered = this.music();

    const typeFilter = this.typeFilter();
    if (typeFilter !== 'all') {
      filtered = filtered.filter(music => music.type === typeFilter);
    }

    const statusFilter = this.statusFilter();
    if (statusFilter !== 'all') {
      filtered = filtered.filter(music => music.status === statusFilter);
    }

    // Apply search filter
    const searchQuery = this.searchQuery().toLowerCase().trim();
    if (searchQuery) {
      filtered = filtered.filter(music =>
        music.title.toLowerCase().includes(searchQuery) ||
        music.artist.toLowerCase().includes(searchQuery) ||
        music.notes?.toLowerCase().includes(searchQuery) ||
        this.getTypeLabel(music.type).toLowerCase().includes(searchQuery)
      );
    }

    // Apply tag filter
    const selectedTags = this.selectedTags();
    if (selectedTags.length > 0) {
      filtered = filtered.filter(music =>
        selectedTags.every(tag => music.tags?.includes(tag))
      );
    }

    return filtered;
  });

  paginatedMusic = computed(() => {
    const music = this.filteredMusic();
    const start = (this.currentPage() - 1) * this.pageSize();
    const end = start + this.pageSize();
    return music.slice(start, end);
  });

  totalFilteredMusic = computed(() => this.filteredMusic().length);

  newMusic: Partial<CreateMusicDto> & { dateStarted?: Date; dateFinished?: Date } = {
    title: '',
    artist: '',
    type: MusicType.album,
    status: MusicStatus.wantToListen,
    dateStarted: undefined,
    dateFinished: undefined,
    rating: undefined,
    notes: '',
    tags: [],
    links: []
  };

  editMusicData: Partial<UpdateMusicDto> = {};

  // Time tracking state
  newMusicTimeHours = 0;
  newMusicTimeMinutes = 0;
  editMusicTimeHours = 0;
  editMusicTimeMinutes = 0;

  // Tags and links input state
  newTagInput = '';
  editTagInput = '';
  newLinkTitle = '';
  newLinkUrl = '';
  editLinkTitle = '';
  editLinkUrl = '';

  ngOnInit() {
    this.loadMusic();
  }

  loadMusic() {
    this.loading.set(true);
    this.musicService.getAllMusic().subscribe({
      next: (music) => {
        this.music.set(music);
        this.loading.set(false);
      },
      error: () => {
        this.loading.set(false);
      }
    });
  }

  setTypeFilter(filter: 'all' | MusicType) {
    this.typeFilter.set(filter);
    this.currentPage.set(1); // Reset to first page when filter changes
  }

  setStatusFilter(filter: 'all' | MusicStatus) {
    this.statusFilter.set(filter);
    this.currentPage.set(1); // Reset to first page when filter changes
  }

  toggleTag(tag: string) {
    const current = this.selectedTags();
    if (current.includes(tag)) {
      this.selectedTags.set(current.filter(t => t !== tag));
    } else {
      this.selectedTags.set([...current, tag]);
    }
    this.currentPage.set(1); // Reset to first page when tags change
  }

  clearFilters() {
    this.searchQuery.set('');
    this.selectedTags.set([]);
    this.typeFilter.set('all');
    this.statusFilter.set('all');
    this.currentPage.set(1);
  }

  toggleFilters() {
    this.showFilters.update(v => !v);
  }

  onPageChange(page: number) {
    this.currentPage.set(page);
  }

  onPageSizeChange(pageSize: number) {
    this.pageSize.set(pageSize);
    // Calculate new current page to stay on approximately the same content
    const firstItemIndex = (this.currentPage() - 1) * this.pageSize();
    const newPage = Math.floor(firstItemIndex / pageSize) + 1;
    this.currentPage.set(newPage);
  }

  getTypeLabel(type: MusicType): string {
    switch (type) {
      case MusicType.album: return 'Album';
      case MusicType.single: return 'Single';
      case MusicType.ep: return 'EP';
    }
  }

  getStatusLabel(status: MusicStatus): string {
    switch (status) {
      case MusicStatus.listening: return 'Currently Listening';
      case MusicStatus.completed: return 'Completed';
      case MusicStatus.wantToListen: return 'Want to Listen';
      case MusicStatus.retired: return 'Retired';
    }
  }

  toggleAddForm() {
    this.showAddForm.update(v => !v);
    if (!this.showAddForm()) {
      this.resetForm();
    }
  }

  resetForm() {
    this.newMusic = {
      title: '',
      artist: '',
      type: MusicType.album,
      status: MusicStatus.wantToListen,
      dateStarted: undefined,
      dateFinished: undefined,
      rating: undefined,
      notes: '',
      coverArt: undefined,
      tags: [],
      links: []
    };
    this.newMusicTimeHours = 0;
    this.newMusicTimeMinutes = 0;
    this.newMusicImagePreview.set(null);
    this.imageError.set(null);
    this.newTagInput = '';
    this.newLinkTitle = '';
    this.newLinkUrl = '';
  }

  updateNewMusicTimeSpent() {
    const totalMinutes = (this.newMusicTimeHours * 60) + this.newMusicTimeMinutes;
    this.newMusic.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
  }

  updateEditMusicTimeSpent() {
    const totalMinutes = (this.editMusicTimeHours * 60) + this.editMusicTimeMinutes;
    this.editMusicData.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
  }

  addTag(target: 'new' | 'edit') {
    const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim();
    if (!input) return;

    if (target === 'new') {
      this.newMusic.tags = [...(this.newMusic.tags || []), input];
      this.newTagInput = '';
    } else {
      this.editMusicData.tags = [...(this.editMusicData.tags || []), input];
      this.editTagInput = '';
    }
  }

  removeTag(index: number, target: 'new' | 'edit') {
    if (target === 'new') {
      this.newMusic.tags = (this.newMusic.tags || []).filter((_, i) => i !== index);
    } else {
      this.editMusicData.tags = (this.editMusicData.tags || []).filter((_, i) => i !== index);
    }
  }

  addLink(target: 'new' | 'edit') {
    const title = target === 'new' ? this.newLinkTitle.trim() : this.editLinkTitle.trim();
    const url = target === 'new' ? this.newLinkUrl.trim() : this.editLinkUrl.trim();
    if (!title || !url) return;

    if (target === 'new') {
      this.newMusic.links = [...(this.newMusic.links || []), { title, url }];
      this.newLinkTitle = '';
      this.newLinkUrl = '';
    } else {
      this.editMusicData.links = [...(this.editMusicData.links || []), { title, url }];
      this.editLinkTitle = '';
      this.editLinkUrl = '';
    }
  }

  removeLink(index: number, target: 'new' | 'edit') {
    if (target === 'new') {
      this.newMusic.links = (this.newMusic.links || []).filter((_, i) => i !== index);
    } else {
      this.editMusicData.links = (this.editMusicData.links || []).filter((_, i) => i !== index);
    }
  }

  addMusic() {
    if (!this.newMusic.title || !this.newMusic.artist || !this.newMusic.type || !this.newMusic.status) return;

    const musicToAdd: CreateMusicDto = {
      title: this.newMusic.title,
      artist: this.newMusic.artist,
      type: this.newMusic.type,
      status: this.newMusic.status,
      dateStarted: this.newMusic.dateStarted ? new Date(this.newMusic.dateStarted) : undefined,
      dateFinished: this.newMusic.dateFinished ? new Date(this.newMusic.dateFinished) : undefined,
      rating: this.newMusic.rating,
      notes: this.newMusic.notes,
      coverArt: this.newMusic.coverArt,
      tags: this.newMusic.tags || [],
      links: this.newMusic.links || []
    };

    this.musicService.createMusic(musicToAdd).subscribe(() => {
      this.loadMusic();
      this.toggleAddForm();
    });
  }

  deleteMusic(music: Music) {
    if (confirm(`Are you sure you want to delete "${music.title}" by ${music.artist}?`)) {
      this.musicService.deleteMusic(music.id).subscribe(() => {
        this.loadMusic();
      });
    }
  }

  startEdit(music: Music) {
    this.editingMusic.set(music);
    this.editMusicData = {
      title: music.title,
      artist: music.artist,
      type: music.type,
      status: music.status,
      dateStarted: music.dateStarted,
      dateFinished: music.dateFinished,
      rating: music.rating,
      notes: music.notes,
      coverArt: music.coverArt,
      tags: [...(music.tags || [])],
      links: [...(music.links || [])],
      timeSpent: music.timeSpent
    };
    // Populate time fields from existing timeSpent
    if (music.timeSpent) {
      this.editMusicTimeHours = Math.floor(music.timeSpent / 60);
      this.editMusicTimeMinutes = music.timeSpent % 60;
    } else {
      this.editMusicTimeHours = 0;
      this.editMusicTimeMinutes = 0;
    }
    this.editMusicImagePreview.set(music.coverArt || null);
    this.showAddForm.set(false);
    this.imageError.set(null);
    this.editTagInput = '';
    this.editLinkTitle = '';
    this.editLinkUrl = '';

    // Scroll to top so the form is visible
    window.scrollTo({ top: 0, behavior: 'smooth' });
  }

  cancelEdit() {
    this.editingMusic.set(null);
    this.editMusicData = {};
    this.editMusicImagePreview.set(null);
    this.imageError.set(null);
    this.editTagInput = '';
    this.editLinkTitle = '';
    this.editLinkUrl = '';
  }

  saveEdit() {
    const music = this.editingMusic();
    if (!music || !this.editMusicData.title || !this.editMusicData.artist || !this.editMusicData.type || !this.editMusicData.status) return;

    const updateData = {
      ...this.editMusicData,
      dateStarted: this.editMusicData.dateStarted ? new Date(this.editMusicData.dateStarted) : undefined,
      dateFinished: this.editMusicData.dateFinished ? new Date(this.editMusicData.dateFinished) : undefined,
    };

    this.musicService.updateMusic(music.id, updateData).subscribe(() => {
      this.loadMusic();
      this.cancelEdit();
    });
  }

  formatDate(date: Date | string): string {
    return new Date(date).toLocaleDateString();
  }

  formatTimeSpent(minutes: number): string {
    const hours = Math.floor(minutes / 60);
    const mins = minutes % 60;

    if (hours === 0) {
      return `${mins}m`;
    } else if (mins === 0) {
      return `${hours}h`;
    } else {
      return `${hours}h ${mins}m`;
    }
  }

  // Image handling methods
  onImageSelected(event: Event, target: 'new' | 'edit' | 'suggest') {
    const input = event.target as HTMLInputElement;
    const file = input.files?.[0];

    if (!file) return;

    this.imageError.set(null);

    if (file.size > this.MAX_IMAGE_SIZE) {
      this.imageError.set(`Image too large. Maximum size is ${this.MAX_IMAGE_SIZE / 1024}KB.`);
      input.value = '';
      return;
    }

    if (!file.type.startsWith('image/')) {
      this.imageError.set('Please select an image file.');
      input.value = '';
      return;
    }

    const reader = new FileReader();
    reader.onload = () => {
      const base64 = reader.result as string;
      if (target === 'new') {
        this.newMusicImagePreview.set(base64);
        this.newMusic.coverArt = base64;
      } else if (target === 'edit') {
        this.editMusicImagePreview.set(base64);
        this.editMusicData.coverArt = base64;
      } else {
        this.suggestMusicImagePreview.set(base64);
        this.suggestedMusic.coverArt = base64;
      }
    };
    reader.readAsDataURL(file);
  }

  clearImage(target: 'new' | 'edit' | 'suggest') {
    if (target === 'new') {
      this.newMusicImagePreview.set(null);
      this.newMusic.coverArt = undefined;
    } else if (target === 'edit') {
      this.editMusicImagePreview.set(null);
      this.editMusicData.coverArt = undefined;
    } else {
      this.suggestMusicImagePreview.set(null);
      this.suggestedMusic.coverArt = undefined;
    }
    this.imageError.set(null);
  }

  // Comments methods
  toggleComments(musicId: string) {
    const expanded = this.expandedComments();
    const isCurrentlyExpanded = expanded[musicId];

    this.expandedComments.set({
      ...expanded,
      [musicId]: !isCurrentlyExpanded
    });

    if (!isCurrentlyExpanded && !this.comments()[musicId]) {
      this.loadComments(musicId);
    }
  }

  loadComments(musicId: string) {
    this.commentsLoading.set({
      ...this.commentsLoading(),
      [musicId]: true
    });

    this.commentsService.getCommentsForMusic(musicId).subscribe({
      next: (comments) => {
        this.comments.set({
          ...this.comments(),
          [musicId]: comments
        });
        this.commentsLoading.set({
          ...this.commentsLoading(),
          [musicId]: false
        });
      },
      error: () => {
        this.commentsLoading.set({
          ...this.commentsLoading(),
          [musicId]: false
        });
      }
    });
  }

  getCommentCount(musicId: string): number {
    return this.comments()[musicId]?.length || 0;
  }

  addComment(musicId: string) {
    const content = this.newCommentContent[musicId];
    if (!content?.trim()) return;

    this.commentsService.addCommentToMusic(musicId, { content }).subscribe({
      next: (comment) => {
        this.comments.set({
          ...this.comments(),
          [musicId]: [comment, ...(this.comments()[musicId] || [])]
        });
        this.newCommentContent[musicId] = '';
      }
    });
  }

  deleteComment(musicId: string, commentId: string) {
    if (!confirm('Are you sure you want to delete this comment?')) return;

    this.commentsService.deleteCommentFromMusic(musicId, commentId).subscribe({
      next: () => {
        this.comments.set({
          ...this.comments(),
          [musicId]: (this.comments()[musicId] || []).filter(c => c.id !== commentId)
        });
      }
    });
  }

  canEditComment(comment: Comment): boolean {
    const user = this.authService.user();
    if (!user) return false;
    return comment.userId === user.id || this.authService.isAdmin();
  }

  canDeleteComment(comment: Comment): boolean {
    const user = this.authService.user();
    if (!user) return false;
    return comment.userId === user.id || this.authService.isAdmin();
  }

  startEditComment(musicId: string, comment: Comment) {
    this.editingCommentId.set(comment.id);
    this.editCommentContent = comment.rawContent ?? comment.content;
  }

  cancelCommentEdit() {
    this.editingCommentId.set(null);
    this.editCommentContent = '';
  }

  saveCommentEdit(musicId: string, commentId: string) {
    if (!this.editCommentContent.trim()) return;

    this.commentsService.updateCommentOnMusic(musicId, commentId, this.editCommentContent).subscribe({
      next: (updatedComment) => {
        this.comments.set({
          ...this.comments(),
          [musicId]: (this.comments()[musicId] || []).map(c =>
            c.id === commentId ? updatedComment : c
          )
        });
        this.cancelCommentEdit();
      }
    });
  }

  // Suggestion methods
  toggleSuggestForm() {
    this.showSuggestForm.update(v => !v);
    if (!this.showSuggestForm()) {
      this.resetSuggestForm();
    }
  }

  resetSuggestForm() {
    this.suggestedMusic = {
      title: '',
      artist: '',
      type: MusicType.album,
      notes: '',
      coverArt: undefined
    };
    this.suggestMusicImagePreview.set(null);
    this.imageError.set(null);
  }

  async submitSuggestion() {
    if (!this.suggestedMusic.title || !this.suggestedMusic.artist) return;

    try {
      await this.suggestionService.createSuggestion({
        entityType: SuggestionEntity.music,
        title: this.suggestedMusic.title,
        artist: this.suggestedMusic.artist,
        type: this.suggestedMusic.type,
        notes: this.suggestedMusic.notes,
        coverArt: this.suggestedMusic.coverArt
      });
      alert('Thank you for your suggestion! It will be reviewed soon.');
      this.toggleSuggestForm();
    } catch {
      alert('Failed to submit suggestion. Please try again.');
    }
  }

  handleCommentEdit(musicId: string, event: { commentId: string; content: string }) {
    this.commentsService.updateCommentOnMusic(musicId, event.commentId, event.content).subscribe({
      next: (updatedComment) => {
        this.comments.set({
          ...this.comments(),
          [musicId]: (this.comments()[musicId] || []).map(c =>
            c.id === event.commentId ? updatedComment : c
          )
        });
      }
    });
  }

  getCommentsSignal(musicId: string) {
    return signal(this.comments()[musicId] || []);
  }
}