/**
 *  Copyright © 2025, Luis Andrés Lange <https://javacomm.net>
 *
 *  Previously released under Apache License 2.0; now licensed under MPL 2.0.
 *
 *  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.
 *
 *  In short:
 *  - This file may be used, modified, and distributed under MPL 2.0 only.
 *  - It may NOT be relicensed under GPL, LGPL, AGPL, or any other Secondary License.
 *
 *  Rationale:
 *  - Ensures that the code remains MPL-2.0.
 *  - Avoids legal conflicts with GPL-licensed libraries (e.g., VideoLAN).
 *  - Maximizes usability for commercial and security-critical applications.
 *
 */
package net.javacomm.restserver;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.javacomm.database.WebdatabaseImpl;
import net.javacomm.facade.DatabaseService;



/**
 * Der Benutzer hat sein Password vergessen und fordert ein neues Password an.
 * 
 * @author llange
 *
 */
@Path("/reset/password")
@Produces(MediaType.TEXT_HTML)
public class ResetPassword {

  final String USER_ID = "userid";
  final String CONFIRMATION_KEY = "confirmationKey";
  final Logger log = LogManager.getLogger(ResetPassword.class);
  private DatabaseService databaseservice;

  public ResetPassword() {
    databaseservice = WebdatabaseImpl.getInstance();
  }



  /**
   * Das Password wird aktualisiert, wenn die UserID und der Bestätigungsschlüssel
   * stimmen.
   * 
   * 
   * @param userid
   *                        die UserID
   * @param confirmationKey
   *                        ein nur einmal gültiger Bestätigungsschlüssel
   * @param lang
   *                        die Sprache
   * 
   * @return {@code true}, das Password wurde geändert
   * 
   * @deprecated As of 260501-PRE2.
   */
  @Deprecated
  @GET
  @Path("{userid}/{confirmationKey}/{lang}")
  public String reset(@PathParam("userid") String userid,
      @PathParam("confirmationKey") String confirmationKey, @PathParam("lang") String lang) {

    log.info("userid=" + userid);
    log.info("confirmationKey=" + confirmationKey);
    log.info("lang=" + lang);

    boolean changePassword = databaseservice.isConfirmationkeyTrue(userid, confirmationKey);
    if (!changePassword) {
      // fordere ein neues Password an
      log.info("neues Password anfordern, altes ist abgelaufen");
      return rejected(lang);
    }
    // Password ändern
    // confirmationflag auf 0 setzen
    databaseservice.updateConfirmationFlag(userid, "", 0);
    boolean changed = databaseservice.changePassword(userid, confirmationKey);

    if (changed) {
      // confirmed_passoword laden
      if (lang.equals("de")) {
        return response(Resource.CONFIRMED_PASSWORD_DE);
      }
      else if (lang.equals("en")) {
        return response(Resource.CONFIRMED_PASSWORD_EN);
      }
      else if (lang.equals("es")) {
        return response(Resource.CONFIRMED_PASSWORD_ES);
      }
      else {
        return response(Resource.CONFIRMED_PASSWORD_EN);
      }
    }
    else {
      // rejected_passoword laden
      log.info("neues Password konnte nicht kopiert werden, deshalb neues Password anfordern");
      return rejected(lang);
    }

  }



  /**
   * Das Password wird aktualisiert, wenn die UserID und der Bestätigungsschlüssel
   * stimmen.
   * 
   * 
   * @param confirmationKey
   *                        ein nur einmal gültiger Bestätigungsschlüssel
   * @param lang
   *                        die Sprache
   * 
   * @return {@code true}, das Password wurde geändert
   * 
   */
  @GET
  @Path("{confirmationKey}/{lang}")
  public String resetNeu(@PathParam("confirmationKey") String confirmationKey,
      @PathParam("lang") String lang) {

    String userid = databaseservice.fetchUserConfirmationKey(confirmationKey);

    boolean changePassword = databaseservice.isConfirmationkeyTrue(userid, confirmationKey);
    if (!changePassword) {
      // fordere ein neues Password an
      log.info("neues Password anfordern, altes ist abgelaufen");
      return rejected(lang);
    }
    // Password ändern
    // confirmationflag auf 0 setzen
    databaseservice.updateConfirmationFlag(userid, "", 0);
    boolean changed = databaseservice.changePassword(userid, confirmationKey);

    if (changed) {
      // confirmed_passoword laden
      if (lang.equals("de")) {
        return response(Resource.CONFIRMED_PASSWORD_DE);
      }
      else if (lang.equals("en")) {
        return response(Resource.CONFIRMED_PASSWORD_EN);
      }
      else if (lang.equals("es")) {
        return response(Resource.CONFIRMED_PASSWORD_ES);
      }
      else {
        return response(Resource.CONFIRMED_PASSWORD_EN);
      }
    }
    else {
      // rejected_passoword laden
      log.info("neues Password konnte nicht kopiert werden, deshalb neues Password anfordern");
      return rejected(lang);
    }

  }



  /**
   * Gib eine HTML-Seite mit "Fordere neues Passwort an" zurück.
   * 
   * @param lang
   *             die Sprachausgabe für die HTML-Seite
   * 
   * @return eine HTML-Seite
   */
  private String rejected(String lang) {
    String responseHtml;
    if (lang.equals("de")) {
      responseHtml = response(Resource.REJECTED_PASSWORD_DE);
    }
    else if (lang.equals("en")) {
      responseHtml = response(Resource.REJECTED_PASSWORD_EN);
    }
    else if (lang.equals("es")) {
      responseHtml = response(Resource.REJECTED_PASSWORD_ES);
    }
    else {
      throw new NotFoundException();
    }
    return responseHtml;
  }



  /**
   * Eine HTML-Datei wird als Antwort an den Anwender geschickt.
   * 
   * @param resource
   *                 eine Resource im JAR-Archiv
   * @return eine Textdatei
   * @throws IOException
   */
  String response(String resource) {
    final int BUFFER_LEN = 2048;
    ByteArrayOutputStream outStream = null;
    if (log.isDebugEnabled()) log.debug("Resource -----> " + resource);
    try(InputStream confirmedStream = getClass().getResourceAsStream(resource);) {
      outStream = new ByteArrayOutputStream(BUFFER_LEN);
      byte buffer[] = new byte[BUFFER_LEN];
      int len;
      while ((len = confirmedStream.read(buffer, 0, BUFFER_LEN)) > 0) {
        outStream.write(buffer, 0, len);
      }
    }
    catch (IOException e) {
      log.error(e.getMessage(), e.getCause());
    }
    return outStream.toString();
  }

}
