package org.example;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

/**
 * Create a Swing GUI with a file menu with (new, new 5 new 10, ---, exit)
 * options and a JBorderLayout using Centre and South. Both start empty.
 * Clicking New creates a set of "Cards" in the South panel, where each card
 * is numbered from 1 to 20 (randomly, without duplication, sorted from
 * lowest to highest). There are from 5 to 10 cards, centred Left-right and
 * top-bottom, with the cards slightly overlapped (about 1/4 their width).
 * Hovering over a card causes it to rise up about 10 pixels. The hover
 * should only apply on the visible part of the card (cards to the right
 * appear to be "over" cards to their left). Clicking on a card causes it to
 * be removed from the South panel and moved to the centre panel (replacing
 * any card that was there). The card in the centre panel should be displayed
 * at full size. The remaining cards "close up" to fill the space left by the
 * removed card. The only difference for New 5 and New 10 is that they create
 * the given number of cards. Also, each New command empties the centre panel.
 * The purpose of Exit should be obvious. Closing the window should
 * likewise close the application.
 */
public class App extends JFrame {
    private JPanel centrePanel;
    private JPanel southPanel;
    private CardPanel centreCard;
    private ArrayList<CardPanel> cards;

    public App() {
        setTitle("Card Game");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);
        setLocationRelativeTo(null);

        // Set up menu bar
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");

        JMenuItem newItem = new JMenuItem("New");
        newItem.addActionListener(e -> createCards(5 + new Random().nextInt(6)));
        fileMenu.add(newItem);

        JMenuItem new5Item = new JMenuItem("New 5");
        new5Item.addActionListener(e -> createCards(5));
        fileMenu.add(new5Item);

        JMenuItem new10Item = new JMenuItem("New 10");
        new10Item.addActionListener(e -> createCards(10));
        fileMenu.add(new10Item);

        fileMenu.addSeparator();

        JMenuItem exitItem = new JMenuItem("Exit");
        exitItem.addActionListener(e -> System.exit(0));
        fileMenu.add(exitItem);

        menuBar.add(fileMenu);
        setJMenuBar(menuBar);

        // Set up main content pane with BorderLayout
        JPanel mainPanel = new JPanel(new BorderLayout());

        // Centre panel
        centrePanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (centreCard != null) {
                    centreCard.paintCentre(g, getWidth(), getHeight());
                }
            }
        };
        centrePanel.setBackground(new Color(199, 199, 199));

        // South panel with custom layout for overlapped cards
        southPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (!cards.isEmpty()) {
                    int panelWidth = getWidth();
                    int panelHeight = getHeight();
                    int cardWidth = 100;
                    int cardHeight = 140;
                    int overlap = cardWidth / 4;
                    int totalWidth = cardWidth + (cards.size() - 1) * (cardWidth - overlap);
                    int startX = (panelWidth - totalWidth) / 2;
                    int startY = (panelHeight - cardHeight) / 2;

                    for (int i = 0; i < cards.size(); i++) {
                        CardPanel card = cards.get(i);
                        int x = startX + i * (cardWidth - overlap);
                        int y = startY + (card.isHovered ? -10 : 0);
                        card.paint(g, x, y, cardWidth, cardHeight);
                    }
                }
            }
        };
        southPanel.setBackground(new Color(199, 199, 199));
        southPanel.setPreferredSize(new Dimension(800, 180));
        southPanel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                updateHoveredCard(e.getX(), e.getY());
            }
        });
        southPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                handleCardClick(e.getX(), e.getY());
            }
        });

        mainPanel.add(centrePanel, BorderLayout.CENTER);
        mainPanel.add(southPanel, BorderLayout.SOUTH);
        mainPanel.add(new JPanel(), BorderLayout.NORTH);
        mainPanel.add(new JPanel(), BorderLayout.EAST);
        mainPanel.add(new JPanel(), BorderLayout.WEST);

        add(mainPanel);

        cards = new ArrayList<>();
        setVisible(true);
    }

    private void createCards(int count) {
        cards.clear();
        centreCard = null;

        Set<Integer> numbers = new HashSet<>();
        Random rand = new Random();
        while (numbers.size() < count) {
            numbers.add(rand.nextInt(20) + 1);
        }

        ArrayList<Integer> sortedNumbers = new ArrayList<>(numbers);
        Collections.sort(sortedNumbers);

        for (int num : sortedNumbers) {
            cards.add(new CardPanel(num));
        }

        southPanel.repaint();
    }

    private void updateHoveredCard(int mouseX, int mouseY) {
        if (cards.isEmpty()) return;

        int panelWidth = southPanel.getWidth();
        int panelHeight = southPanel.getHeight();
        int cardWidth = 100;
        int cardHeight = 140;
        int overlap = cardWidth / 4;
        int totalWidth = cardWidth + (cards.size() - 1) * (cardWidth - overlap);
        int startX = (panelWidth - totalWidth) / 2;
        int startY = (panelHeight - cardHeight) / 2;

        boolean repaintNeeded = false;
        boolean foundHovered = false;

        // Iterate from right to left to find topmost card under cursor
        for (int i = cards.size() - 1; i >= 0; i--) {
            CardPanel card = cards.get(i);
            int x = startX + i * (cardWidth - overlap);

            boolean wasHovered = card.isHovered;

            if (!foundHovered && isPointInCard(mouseX, mouseY, x, startY, cardWidth, cardHeight, i)) {
                card.isHovered = true;
                foundHovered = true;
            } else {
                card.isHovered = false;
            }

            if (wasHovered != card.isHovered) {
                repaintNeeded = true;
            }
        }

        if (repaintNeeded) {
            southPanel.repaint();
        }
    }

    private boolean isPointInCard(int px, int py, int cardX, int cardY, int cardWidth, int cardHeight, int cardIndex) {
        // Check if point is within the visible part of the card (accounting for overlap)
        int rightBound = cardX + cardWidth;
        // If there's a card to the right, reduce the right bound
        if (cardIndex < cards.size() - 1) {
            rightBound = cardX + cardWidth - (cardWidth / 4) / 2;
        }
        return px >= cardX && px <= rightBound && py >= cardY && py <= cardY + cardHeight;
    }

    private void handleCardClick(int mouseX, int mouseY) {
        if (cards.isEmpty()) return;

        int panelWidth = southPanel.getWidth();
        int panelHeight = southPanel.getHeight();
        int cardWidth = 100;
        int cardHeight = 140;
        int overlap = cardWidth / 4;
        int totalWidth = cardWidth + (cards.size() - 1) * (cardWidth - overlap);
        int startX = (panelWidth - totalWidth) / 2;
        int startY = (panelHeight - cardHeight) / 2;

        for (int i = 0; i < cards.size(); i++) {
            CardPanel card = cards.get(i);
            int x = startX + i * (cardWidth - overlap);

            if (isPointInCard(mouseX, mouseY, x, startY, cardWidth, cardHeight, i)) {
                centreCard = card;
                cards.remove(i);
                southPanel.repaint();
                centrePanel.repaint();
                break;
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(App::new);
    }

    static class CardPanel {
        int number;
        boolean isHovered;

        CardPanel(int number) {
            this.number = number;
            this.isHovered = false;
        }

        void paint(Graphics g, int x, int y, int width, int height) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // Draw card background
            g2d.setColor(new Color(255, 220, 100));
            g2d.fillRoundRect(x, y, width, height, 10, 10);

            // Draw card border
            g2d.setColor(Color.BLACK);
            g2d.setStroke(new BasicStroke(2));
            g2d.drawRoundRect(x, y, width, height, 10, 10);

            // Draw number at top-left
            g2d.setColor(Color.BLACK);
            g2d.setFont(new Font("Arial", Font.BOLD, 24));
            FontMetrics fm = g2d.getFontMetrics();
            String text = String.valueOf(number);
            int textX = x + 8;
            int textY = y + 8 + fm.getAscent();
            g2d.drawString(text, textX, textY);
        }

        void paintCentre(Graphics g, int panelWidth, int panelHeight) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            int width = 100;
            int height = 140;
            int x = (panelWidth - width) / 2;
            int y = (panelHeight - height) / 2;

            // Draw card background
            g2d.setColor(new Color(255, 220, 100));
            g2d.fillRoundRect(x, y, width, height, 10, 10);

            // Draw card border
            g2d.setColor(Color.BLACK);
            g2d.setStroke(new BasicStroke(2));
            g2d.drawRoundRect(x, y, width, height, 10, 10);

            // Draw number at top-left
            g2d.setColor(Color.BLACK);
            g2d.setFont(new Font("Arial", Font.BOLD, 24));
            FontMetrics fm = g2d.getFontMetrics();
            String text = String.valueOf(number);
            int textX = x + 8;
            int textY = y + 8 + fm.getAscent();
            g2d.drawString(text, textX, textY);
        }
    }
}
