package sbu.javafx;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javafx.scene.Parent;

public class MusicController
{

    @FXML private VBox songContainer;
    @FXML private Label nowPlayingLabel;
    @FXML private Label currentTrackTitle;
    @FXML private Label timeLabel;
    @FXML private Slider progressSlider;
    @FXML private Slider volumeSlider;
    @FXML private Button playPauseButton;
    @FXML private Button repeatButton;
    @FXML private Button shuffleButton;
    @FXML private Button likeButton;
    @FXML private StackPane visualizerContainer;

    private MediaPlayer mediaPlayer;
    private int currentSongIndex = 0;
    private boolean isRepeat = false;
    private boolean isShuffle = false;
    private boolean isLiked = false;
    private final Random random = new Random();
    private Timeline visualizerAnimation;

    private final String[] songFiles = {
            "Maison.mp3",
            "KUSURA_BAKMA.mp3",
            "Hiting_Motion.mp3",
            "Lost_in_the_haze.mp3",
            "North.mp3",
            "Longing.mp3",
            "After_Math.mp3",
            "On_The_Roads.mp3",
            "Bumpup.mp3",
            "SEVMEYİ_DENEMEDİN.mp3"

    };

    private final Map<String, String> songDisplayNames = new HashMap<>();
    private static final ObservableList<String> playlist = FXCollections.observableArrayList();
    private static final ObservableList<String> favorites = FXCollections.observableArrayList();

    @FXML
    public void initialize()
    {
        for (int i = 0; i < songFiles.length; i++)
        {
            createSongCard(i);
        }
        setupVolumeControl();
        createVisualizer();
    }

    private void createVisualizer()
    {
        HBox bars = new HBox(3);
        bars.setAlignment(Pos.BOTTOM_CENTER);
        for (int i = 0; i < 4; i++)
        {
            Region bar = new Region();
            bar.setPrefWidth(4);
            bar.setPrefHeight(5);
            bar.setStyle("-fx-background-color: #1DB954; -fx-background-radius: 2;");
            bars.getChildren().add(bar);
        }
        visualizerContainer.getChildren().add(bars);

        visualizerAnimation = new Timeline();
        for (Node node : bars.getChildren())
        {
            double randomHeight = 10 + Math.random() * 15;
            KeyFrame kf = new KeyFrame(Duration.millis(150 + Math.random() * 100),
                    new KeyValue(((Region)node).prefHeightProperty(), randomHeight)
            );
            visualizerAnimation.getKeyFrames().add(kf);
        }
        visualizerAnimation.setCycleCount(Timeline.INDEFINITE);
        visualizerAnimation.setAutoReverse(true);
    }

    private void updateLikeButton(String displayName)
    {
        if (displayName == null || likeButton == null)
        {
            if (likeButton != null)
            {
                likeButton.setText("♡");
                likeButton.getStyleClass().remove("btn-heart-liked");
            }
            return;
        }

        if (favorites.contains(displayName))
        {
            likeButton.setText("♥");
            if (!likeButton.getStyleClass().contains("btn-heart-liked"))
            {
                likeButton.getStyleClass().add("btn-heart-liked");
            }
        } else
        {
            likeButton.setText("♡");
            likeButton.getStyleClass().remove("btn-heart-liked");
        }
    }

    @FXML
    private void toggleLike()
    {
        String currentSongName = nowPlayingLabel.getText();
        if (currentSongName.equals("None") || currentSongName.equals("Not Playing")) return;

        isLiked = !isLiked;
        if (isLiked)
        {
            likeButton.setText("♥");
            likeButton.setStyle("-fx-text-fill: #ff4d4d; -fx-font-size: 16px;");
            if (!favorites.contains(currentSongName)) favorites.add(currentSongName);
        } else
        {
            likeButton.setText("♡");
            likeButton.setStyle("-fx-text-fill: inherit; -fx-font-size: 16px;");
            favorites.remove(currentSongName);
        }
    }

    private void createSongCard(int index)
    {
        String fileName = songFiles[index];
        String displayName = cleanFileName(fileName);

        HBox card = new HBox(14);
        card.setAlignment(Pos.CENTER_LEFT);
        card.getStyleClass().add("song-card");


        ImageView coverView = createCoverImageView(fileName);

        VBox infoBox = new VBox(4);
        Label titleLabel = new Label(displayName);
        titleLabel.getStyleClass().add("song-title");


        Label subtitleLabel = new Label("00:00");
        subtitleLabel.getStyleClass().add("song-subtitle");


        subtitleLabel.getStyleClass().add("song-meta");
        infoBox.getChildren().addAll(titleLabel, subtitleLabel);

        Region spacer = new Region();
        HBox.setHgrow(spacer, Priority.ALWAYS);

        Button cardLikeBtn = new Button(favorites.contains(displayName) ? "♥" : "♡");
        cardLikeBtn.getStyleClass().add("btn-ghost");
        cardLikeBtn.setStyle("-fx-font-size: 16px; -fx-text-fill: #ff4d6d;");
        cardLikeBtn.setOnAction(event ->
        {
            if (favorites.contains(displayName))
            {
                favorites.remove(displayName);
                cardLikeBtn.setText("♡");
            } else {
                favorites.add(displayName);
                cardLikeBtn.setText("♥");
            }
            updateLikeButton(displayName);
        });

        Button addButton = new Button("+");
        addButton.getStyleClass().add("btn-ghost");
        addButton.setStyle("-fx-font-size: 18px;");
        addButton.setOnAction(event ->
        {
            if (!playlist.contains(displayName))
            {
                playlist.add(displayName);
            }
        });

        Button playButton = new Button("▶");
        playButton.getStyleClass().add("btn-green-small");
        playButton.setOnAction(event ->
        {
            currentSongIndex = index;
            playMedia(fileName);
        });

        cardLikeBtn.setOnMouseClicked(e -> e.consume());
        addButton.setOnMouseClicked(e -> e.consume());
        playButton.setOnMouseClicked(e -> e.consume());

        card.getChildren().addAll(coverView, infoBox, spacer, cardLikeBtn, addButton, playButton);
        songContainer.getChildren().add(card);
    }

    private void playMedia(String fileName)
    {
        if (mediaPlayer != null)
        {
            mediaPlayer.stop(); mediaPlayer.dispose();
        }

        URL resource = getClass().getResource("/music/" + fileName);
        if (resource == null) return;

        Media media = new Media(resource.toExternalForm());
        mediaPlayer = new MediaPlayer(media);
        mediaPlayer.volumeProperty().bind(volumeSlider.valueProperty());

        mediaPlayer.setOnReady(() -> {
            String name = cleanFileName(fileName);
            nowPlayingLabel.setText(name);
            currentTrackTitle.setText(name);
            playPauseButton.setText("Pause");
            visualizerAnimation.play();

            isLiked = favorites.contains(name);
            likeButton.setText(isLiked ? "♥" : "♡");
            likeButton.setStyle(isLiked ? "-fx-text-fill: #ff4d4d; -fx-font-size: 16px;" : "");
        });

        mediaPlayer.currentTimeProperty().addListener((obs, old, cur) ->
        {
            timeLabel.setText(formatDuration(cur) + " / " + formatDuration(media.getDuration()));
            if (!progressSlider.isValueChanging())
            {
                progressSlider.setValue((cur.toSeconds() / media.getDuration().toSeconds()) * 100);
            }
        });

        mediaPlayer.setOnEndOfMedia(this::nextTrack);
        mediaPlayer.play();
    }

    private ImageView createCoverImageView(String mp3FileName)
    {
        String baseName = mp3FileName.substring(0, mp3FileName.lastIndexOf("."));
        String[] extensions = {".jpg", ".jpeg", ".png", ".webp"};
        for (String ext : extensions)
        {
            URL url = getClass().getResource("/music/" + baseName + ext);
            if (url != null)
            {
                ImageView iv = new ImageView(new Image(url.toExternalForm()));
                iv.setFitWidth(50); iv.setFitHeight(50); iv.setPreserveRatio(true);
                return iv;
            }
        }
        return new ImageView();
    }

    private void loadMetadata(String fileName, Label metaLabel)
    {
        URL resource = getClass().getResource("/music/" + fileName);
        if (resource == null) return;

        Media media = new Media(resource.toExternalForm());
        MediaPlayer tempPlayer = new MediaPlayer(media);

        tempPlayer.setOnReady(() ->
        {
            metaLabel.setText(formatDuration(media.getDuration()));
            tempPlayer.dispose();
        });
    }

    @FXML private void nextTrack()
    {
        if (isShuffle) currentSongIndex = random.nextInt(songFiles.length);
        else currentSongIndex = (currentSongIndex + 1) % songFiles.length;
        playMedia(songFiles[currentSongIndex]);
    }

    @FXML private void previousTrack()
    {
        currentSongIndex = (currentSongIndex - 1 + songFiles.length) % songFiles.length;
        playMedia(songFiles[currentSongIndex]);
    }

    @FXML private void togglePlayPause()
    {
        if (mediaPlayer == null) return;
        if (mediaPlayer.getStatus() == MediaPlayer.Status.PLAYING)
        {
            mediaPlayer.pause();
            playPauseButton.setText("Play");
            visualizerAnimation.pause();
        } else
        {
            mediaPlayer.play();
            playPauseButton.setText("Pause");
            visualizerAnimation.play();
        }
    }

    @FXML private void toggleRepeat()
    {
        isRepeat = !isRepeat; repeatButton.setStyle(isRepeat ? "-fx-text-fill: #1DB954;" : "");
    }

    @FXML private void toggleShuffle()
    {
        isShuffle = !isShuffle; shuffleButton.setStyle(isShuffle ? "-fx-text-fill: #1DB954;" : "");
    }

    private void setupVolumeControl()
    {
        volumeSlider.setValue(0.5);
    }

    private String cleanFileName(String f)
    {
        return f.replace(".mp3", "").replace("_", " ").replace("-", " ");
    }

    private String formatDuration(Duration d)
    {
        int s = (int) Math.floor(d.toSeconds()); return String.format("%02d:%02d", s / 60, s % 60);
    }


    @FXML
    private void goToPlaylistScene(ActionEvent event) throws IOException
    {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Playlist-view.fxml"));
        Parent root = loader.load();

        PlaylistController controller = loader.getController();
        controller.setPlaylist(playlist);
        controller.setPreviousScene(((Node) event.getSource()).getScene());

        Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        stage.setTitle("Playlist");
        stage.setScene(new Scene(root));
    }

    @FXML
    private void goToFavoritesScene(ActionEvent event) throws IOException
    {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("Playlist-view.fxml"));
        Parent root = loader.load();

        PlaylistController controller = loader.getController();
        controller.setPlaylist(favorites);
        controller.setPreviousScene(((Node) event.getSource()).getScene());

        Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        stage.setTitle("Favorites");
        stage.setScene(new Scene(root));
    }
}