/**
 *  Copyright © 2026, Luis Andrés Lange <https://javacomm.net>
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *  ----------------------------------------------------------------------------
 *
 *  Exhibit B - "Incompatible With Secondary Licenses" Notice
 *
 *  This Source Code Form is "Incompatible With Secondary Licenses",
 *  as defined by the Mozilla Public License, v. 2.0.
 *
 */
package net.javacomm.client.chat;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.MediaType;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.nexuswob.gui.JOkDialog;
import org.nexuswob.gui.TableModel3;
import org.nexuswob.util.Cell;
import org.nexuswob.util.Util.Record;
import net.javacomm.client.resource.Resource;
import net.javacomm.multilingual.Babelfish;
import net.javacomm.multilingual.MultilingualButton;
import net.javacomm.multilingual.MultilingualString;
import net.javacomm.multilingual.schema.ISO639;
import net.javacomm.multilingual.schema.KEY;
import net.javacomm.protocol.UserOnline;
import net.javacomm.restserver.MessageBodyUserOnline;
import net.javacomm.share.Constants;
import net.javacomm.window.manager.Control;



/**
 * Dieses Panel enthält Onlinezähler, Onlineliste und Suchfeld.
 */
@SuppressWarnings("serial")
public class JPrivateChatPanel extends JPanel implements Babelfish {

  private final static Logger log = LogManager.getLogger(JPrivateChatPanel.class);

  private JScrollPane scrollTable = new JScrollPane();
  private JTable table = new JTable();
  private TableModel3 model = new TableModel3();
  private ColorRenderer cRenderer = new ColorRenderer();
  ArrayList<UserOnline> onlinelist = new ArrayList<>();
  private CountUserPanel countUserPanel = new CountUserPanel();
  private JTableHeader header;
  private HeaderRenderer headerrenderer = new HeaderRenderer();
  private JSearchTextfield searchfield = new JSearchTextfield();
  private MultilingualString selftalk = new MultilingualString(KEY.STRING_EINSAME_SEELEN);
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  private MouseAction mouseAction = new MouseAction();
  private GridBagLayout gridbag = new GridBagLayout();
  private GridBagConstraints con = new GridBagConstraints();
  private JSeparator separator = new JSeparator();
  private MultilingualButton cerrarBoton = new MultilingualButton(KEY.BUTTON_SCHLIESSEN);
  private JPanel panSouth = new JPanel(new FlowLayout(FlowLayout.CENTER));
  private String nickname;

  public JPrivateChatPanel() {
    setLayout(gridbag);
    model.setHeader("");
    table.setModel(model);
    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    // table.setAutoResizeMode (JTable.AUTO_RESIZE_OFF);
    header = table.getTableHeader();
    header.setReorderingAllowed(false);
    header.setDefaultRenderer(headerrenderer);
    headerrenderer.setHorizontalAlignment(SwingConstants.CENTER);

    table.addMouseListener(mouseAction);
    table.setDefaultRenderer(String.class, cRenderer);
    cRenderer.setHorizontalAlignment(SwingConstants.CENTER);
    // Double-click to chat.
//    Haz doble clic para chatear.
//    table.setToolTipText(doubleclick.toString());
    table.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    table.setRowHeight(28);
    scrollTable.setViewportView(table);
    scrollTable.getHorizontalScrollBar().setUnitIncrement(12);
    scrollTable.getVerticalScrollBar().setUnitIncrement(14);

    scrollTable.setBorder(null);
    scrollTable.getViewport().setBackground(Resource.JQUERY_TEXTBRAUN);

    con.gridx = 0;
    con.gridy = 0;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 1.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, 0, 0, 0);
    con.anchor = GridBagConstraints.NORTH;
    add(countUserPanel, con);

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.BOTH;
    con.weightx = 1.0;
    con.weighty = 1.0;
    con.insets = new Insets(0, 0, 0, 0);
    con.anchor = GridBagConstraints.NORTH;
    add(scrollTable, con);

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 1.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, 12, 0, 12);
    con.anchor = GridBagConstraints.NORTH;
    add(searchfield, con);
    searchfield.addSearchfieldListener(event -> {
      String pattern = searchfield.getText().length() == 0 ? "" : searchfield.getText();
      Thread.startVirtualThread(() -> findUserOnlineByPattern(pattern));
    });

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.fill = GridBagConstraints.HORIZONTAL;
    con.weightx = 1.0;
    con.weighty = 0.0;
    con.insets = new Insets(24, 12, 12, 12);
    con.anchor = GridBagConstraints.NORTH;
    add(separator, con);

    con.gridx = 0;
    con.gridy++;
    con.gridwidth = 1;
    con.gridheight = 1;
    con.fill = GridBagConstraints.NONE;
    con.weightx = 0.0;
    con.weighty = 0.0;
    con.insets = new Insets(0, 12, 12, 12);
    con.anchor = GridBagConstraints.EAST;
    gridbag.setConstraints(panSouth, con);
    add(panSouth);
    panSouth.add(cerrarBoton);
    cerrarBoton.addActionListener(event -> {
      changes.firePropertyChange(JPrivateChatPanel.class.getName(), Control.NULL, Control.CLOSE);
    });

  }



  /**
   * Die Onlineuser werden aus der Datenbank abgefragt.
   * 
   * @param pattern
   *                das Suchmuster aus dem Eingabefeld
   */
  public void findUserOnlineByPattern(String pattern) {
    ClientConfig config = new ClientConfig();
    config.property(ClientProperties.CONNECT_TIMEOUT, 2000).property(ClientProperties.READ_TIMEOUT, 3000);
    try(Client client = ClientBuilder.newClient(config)) {
      client.register(MessageBodyUserOnline.class);
      WebTarget target = client
          .target(Constants.PROTOCOL + Constants.DOMAIN + "/javacommserver/user/read/online")
          .queryParam("pattern", pattern);
      GenericType<ArrayList<UserOnline>> configType = new GenericType<>() {};
      ArrayList<UserOnline> liste = target.request(MediaType.APPLICATION_JSON).get(configType);
      EventQueue.invokeLater(() -> setUserList(liste));
    }
    catch (Exception e) {
      log.warn(e.getMessage());
    }
  }



  public void addPrivatechatListener(PropertyChangeListener l) {
    changes.addPropertyChangeListener(l);
  }



  public void removeAllListener() {
    for (PropertyChangeListener listener : changes.getPropertyChangeListeners()) {
      removePrivatechatListener(listener);
    }

    for (ActionListener al : cerrarBoton.getActionListeners()) {
      cerrarBoton.removeActionListener(al);
    }

    table.removeMouseListener(mouseAction);

  }



  public void removePrivatechatListener(PropertyChangeListener l) {
    changes.removePropertyChangeListener(l);
  }



  @Override
  public void setLanguage(ISO639 code) {
    cerrarBoton.setLanguage(code);
    searchfield.setLanguage(code);
  }



  void setNickname(String value) {
    nickname = value;
  }



  /**
   * Zeige alle Anwender, die online sind. Der Aufrufer selber wird nicht
   * angezeigt.
   * 
   * @param list
   *             diese Anwender sind online
   */
  public void setUserList(List<UserOnline> list) {

//    log.info("Start liste Online {}", list.size());

    list.removeIf(online -> online.getNickname().equals(nickname));
//    log.info("updateNickname={}, done {}", nickname, done);
//    log.info("Nach liste Online {}", list.size());

    onlinelist.clear();
    onlinelist.addAll(list);

    model.removeAll();

    onlinelist.forEach(userlist -> {
      Record record = new Record();

      Cell<String> cellNickname = new Cell<>();
      cellNickname.setValue(userlist.getNickname());

      record.add(cellNickname);
      model.addRow(record);

    });
    countUserPanel.setCount(model.getRowCount());

  }



  public void updateColors() {
    searchfield.updateColors();
  }

  /**
   * Jeder Anwender wird mit seinem Nickname und Farbeinstellungen angezeigt.
   */
  class ColorRenderer extends JLabel implements TableCellRenderer {

    private static final long serialVersionUID = 1483352116438614471L;

    public ColorRenderer() {
      setOpaque(true);
    }



    @Override
    public Component getTableCellRendererComponent(JTable table, Object str, boolean isSelected,
        boolean hasFocus, int row, int column) {

      try {
        setBackground(new Color(onlinelist.get(row).getBackground()));
        setForeground(new Color(onlinelist.get(row).getForeground()));
        setText((String) str);
      }
      catch (Exception e) {
        log.info(e.getMessage(), e.getCause());
      }
      return this;
    }

  }

  /**
   * Der HeaderRenderer sorgt für eine einfarbige Hintergrundfläche. Nichts ist
   * mehr augegraut.
   */
  private class HeaderRenderer extends JLabel implements TableCellRenderer {
    private static final long serialVersionUID = 1483352116438614471L;

    public HeaderRenderer() {
      setOpaque(true);
    }



    @Override
    public Component getTableCellRendererComponent(JTable table, Object str, boolean isSelected,
        boolean hasFocus, int row, int column) {

      if (column == 0) {
        setBorder(new EmptyBorder(0, 0, 0, 0));
      }

      setBackground(Resource.JQUERY_ORANGE);

      setText((String) str);
      return this;
    }
  }

  /***************************************************************************/
  /*                                                                         */
  /* Innerclass MouseAction */
  /*                                                                         */
  /***************************************************************************/

  class MouseAction extends MouseAdapter {

    int selectedRow;
    JOkDialog okDialog;

    public MouseAction() {}



    @Override
    public void mouseReleased(MouseEvent event) {
      Object obj;
      // String nickname; //Vorsicht Nickname ist nicht eindeutig, weil der
      // nickname sich ändern kann
      obj = event.getSource();
      if (obj.equals(table) && event.getClickCount() >= 2) {
        if (event.getButton() == MouseEvent.BUTTON1) {
          selectedRow = table.getSelectedRow();
          String tableNickame = model.getValueAt(selectedRow, 0).toString();
          if (tableNickame.equals(nickname)) {
            JOptionPane.showMessageDialog(null, selftalk.toString(), "1:1 Chat", JOptionPane.WARNING_MESSAGE);
          }
          else {
            // Ziel nickname zu diesem User eine Verbindung aufbauen
            changes.firePropertyChange(tableNickame, Control.NULL, Control.HIT);
          }
        }
      }
    }

  }
}
