/**
 * This file is part of the Meeds project (https://meeds.io/).
 *
 * Copyright (C) 2020 - 2025 Meeds Association contact@meeds.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.exoplatform.social.core.jpa.storage.entity;

import java.util.Date;

import org.exoplatform.social.core.relationship.model.Relationship.Type;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.persistence.UniqueConstraint;

@Entity(name = "SocConnection")
@Table(name = "SOC_CONNECTIONS",
       uniqueConstraints=@UniqueConstraint(columnNames = {"SENDER_ID", "RECEIVER_ID"}))
@NamedQueries({
        @NamedQuery(name = "getRelationships",
                query = "select r from SocConnection r"),
        @NamedQuery(name = "SocConnection.findConnectionsByIdentityIds",
                query = "SELECT c FROM SocConnection c WHERE (c.sender.id = :identityId AND c.receiver.id in (:ids) ) OR (c.receiver.id = :identityId AND c.sender.id in (:ids) )"),
        @NamedQuery(name = "SocConnection.findConnectionBySenderAndReceiver",
                query = "SELECT c FROM SocConnection c WHERE c.sender.id = :sender AND c.receiver.id = :reciver"),
        @NamedQuery(name = "SocConnection.findConnectionBySenderAndReceiverWithStatus",
                query = "SELECT c FROM SocConnection c WHERE c.sender.id = :sender AND c.receiver.id = :reciver AND c.status = :status"),
        @NamedQuery(name = "SocConnection.deleteConnectionByIdentity",
                query = "DELETE FROM SocConnection c WHERE c.sender.id = :identityId OR c.receiver.id = :identityId"),
        @NamedQuery(name = "SocConnection.getConnectionIdsWithStatus", query = "SELECT c.sender.id, c.receiver.id FROM SocConnection c WHERE (c.sender.id = :identityId OR c.receiver.id = :identityId) AND c.status = :status"),
        @NamedQuery(name = "SocConnection.getConnectionsWithStatus", query = "SELECT c FROM SocConnection c WHERE (c.sender.id = :identityId OR c.receiver.id = :identityId) AND c.status = :status AND c.sender.enabled = true AND c.receiver.enabled = true AND c.sender.deleted = false AND c.receiver.deleted = false order by c.updatedDate DESC"),
        @NamedQuery(name = "SocConnection.countConnectionsWithStatus", query = "SELECT count(distinct c.id) from SocConnection c WHERE (c.sender.id = :identityId or c.receiver.id = :identityId) AND c.status = :status"),
        @NamedQuery(name = "SocConnection.getConnectionsWithoutStatus", query = "SELECT c AS receiver FROM SocConnection c WHERE (c.sender.id = :identityId OR c.receiver.id = :identityId)"),
        @NamedQuery(name = "SocConnection.countConnectionsWithoutStatus", query = "SELECT count(distinct c.id) from SocConnection c WHERE (c.sender.id = :identityId or c.receiver.id = :identityId)"),
        @NamedQuery(name = "SocConnection.getReceiverBySenderWithStatus", query = "SELECT c FROM SocConnection c WHERE c.sender.id = :identityId AND c.status = :status"),
        @NamedQuery(name = "SocConnection.getReceiverIdsBySenderWithStatus", query = "SELECT c.receiver.id FROM SocConnection c WHERE c.sender.id = :identityId AND c.status = :status"),
        @NamedQuery(name = "SocConnection.getReceiverIdsBySenderWithoutStatus", query = "SELECT c.receiver.id FROM SocConnection c WHERE c.sender.id = :identityId"),
        @NamedQuery(name = "SocConnection.getReceiverBySenderWithoutStatus", query = "SELECT c FROM SocConnection c WHERE c.sender.id = :identityId"),
        @NamedQuery(name = "SocConnection.getSenderByReceiverWithStatus", query = "SELECT c FROM SocConnection c WHERE c.receiver.id = :identityId AND c.status = :status"),
        @NamedQuery(name = "SocConnection.getSenderIdsByReceiverWithStatus", query = "SELECT c.sender.id FROM SocConnection c WHERE c.receiver.id = :identityId AND c.status = :status"),
        @NamedQuery(name = "SocConnection.getSenderIdsByReceiverWithoutStatus", query = "SELECT c.sender.id FROM SocConnection c WHERE c.receiver.id = :identityId"),
        @NamedQuery(name = "SocConnection.getSenderByReceiverWithoutStatus", query = "SELECT c FROM SocConnection c WHERE c.receiver.id = :identityId"),
        @NamedQuery(name = "SocConnection.countReceiverBySenderWithStatus", query = "SELECT count(distinct c.receiver.id) FROM SocConnection c WHERE c.sender.id = :identityId AND c.status = :status"),
        @NamedQuery(name = "SocConnection.countReceiverBySenderWithoutStatus", query = "SELECT count(distinct c.receiver.id) FROM SocConnection c WHERE c.sender.id = :identityId"),
        @NamedQuery(name = "SocConnection.countSenderByReceiverWithStatus", query = "SELECT count(distinct c.sender.id) FROM SocConnection c WHERE c.receiver.id = :identityId AND c.status = :status"),
        @NamedQuery(name = "SocConnection.countSenderByReceiverWithoutStatus", query = "SELECT count(distinct c.sender.id) FROM SocConnection c WHERE c.receiver.id = :identityId"),
        @NamedQuery(name = "SocConnection.migrateSenderId", query = "UPDATE SocConnection c SET c.sender.id = :newId WHERE c.sender.id = :oldId"),
        @NamedQuery(name = "SocConnection.migrateReceiverId", query = "UPDATE SocConnection c SET c.receiver.id = :newId WHERE c.receiver.id = :oldId")
})
public class ConnectionEntity {

  @Id
  @SequenceGenerator(name="SEQ_SOC_CONNECTIONS_ID", sequenceName="SEQ_SOC_CONNECTIONS_ID", allocationSize = 1)
  @GeneratedValue(strategy=GenerationType.AUTO, generator="SEQ_SOC_CONNECTIONS_ID")
  @Column(name = "CONNECTION_ID")
  private Long id;

  @ManyToOne(fetch = FetchType.EAGER, optional = false)
  @JoinColumn(name = "SENDER_ID", referencedColumnName = "IDENTITY_ID")
  private IdentityEntity sender;

  @ManyToOne(fetch = FetchType.EAGER, optional = false)
  @JoinColumn(name = "RECEIVER_ID", referencedColumnName = "IDENTITY_ID")
  private IdentityEntity receiver;
  
  @Enumerated
  @Column(name="STATUS", nullable = false)
  private Type status;
  
    @Temporal(TemporalType.TIMESTAMP)
  @Column(name="UPDATED_DATE", nullable = false)
  private Date updatedDate = new Date();

  public ConnectionEntity() {
  }

  public ConnectionEntity(IdentityEntity sender, IdentityEntity receiver) {
    this.sender = sender;
    this.receiver = receiver;
  }

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public IdentityEntity getSender() {
    return sender;
  }

  public void setSender(IdentityEntity sender) {
    this.sender = sender;
  }

  public IdentityEntity getReceiver() {
    return receiver;
  }

  public void setReceiver(IdentityEntity receiver) {
    this.receiver = receiver;
  }

  public Type getStatus() {
    return status;
  }

  public void setStatus(Type status) {
    if (status == Type.ALL) {
      throw new IllegalArgumentException("Illegal status ["+status+"]");
    }
    this.status = status;
  }

  public Date getUpdatedDate() {
    return updatedDate;
  }

  public void setUpdatedDate(Date updatedDate) {
    this.updatedDate = updatedDate;
  }

}
