/* Copyright 2014-2023 askanimus@gmail.com */

/* This File is part of "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).  If not, see <http://www.gnu.org/licenses/>.
 *
 * Diese Datei ist Teil von "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) ist Freie Software: Sie können es unter den Bedingungen
 * der GNU General Public License, wie von der Free Software Foundation,
 * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
 * veröffentlichten Version, weiter verteilen und/oder modifizieren.
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) wird in der Hoffnung, dass es nützlich sein wird, aber
 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
 * Siehe die GNU General Public License für weitere Details.
 *
 * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
 * Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
 */
package askanimus.arbeitszeiterfassung2.arbeitswoche;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.PopupMenu;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;

import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;

import java.util.Calendar;

import askanimus.arbeitszeiterfassung2.arbeitsplatz.Arbeitsplatz;
import askanimus.arbeitszeiterfassung2.arbeitstag.Arbeitstag;
import askanimus.arbeitszeiterfassung2.arbeitstag.ArbeitstagExpandListAdapter;
import askanimus.arbeitszeiterfassung2.Datum;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.Uhrzeit;
import askanimus.arbeitszeiterfassung2.setup.ISettings;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.IZusatzfeld;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzWertListe;
import askanimus.arbeitszeiterfassung2.zusatzeintrag.ZusatzWertViewAdapter;

/**
 * @author askanimus@gmail.com on 19.08.15.
 */
public class ArbeitswocheFragment extends Fragment
        implements View.OnClickListener,
        PopupMenu.OnMenuItemClickListener {

    private static final String ARG_JAHR = "jahr";
    private static final String ARG_MONAT = "monat";
    private static final String ARG_TAG = "tag";

    // statische Anzeigeelemente
    private RelativeLayout      cErgebnis;
    private TextView            tWoche;
    private TextView            tDatum;
    private ExpandableListView  lTage;

    // Aktuell zu haltende Elemente der Anzeige
    private TextView        tSoll;
    private TextView        tIst;
    private TextView        tDifferenz;
    private TextView        tStundenlohn;

    // Sonstige Werte
    private LinearLayout    cSonstige;
    ZusatzWertViewAdapter mAdapter_kopf;
    private RecyclerView    lZusatzwerte;

    private ImageView       iCompact;
    private boolean         isCompact;

    // die Daten der Woche
    private Arbeitswoche mWoche;

    private Context mContext;
    private ArbeitsWocheMainCallbacks mCallbackMain;
    private ArbeitsWocheCallbacks mCallback;


    /*
      * Neue Instanz anlegen
      */
    public static ArbeitswocheFragment newInstance(Datum cal) {
        ArbeitswocheFragment fragment = new ArbeitswocheFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_JAHR, cal.get(Calendar.YEAR));
        args.putInt(ARG_MONAT, cal.get(Calendar.MONTH));
        args.putInt(ARG_TAG, cal.get(Calendar.DAY_OF_MONTH));
        fragment.setArguments(args);

        return fragment;
    }


    // den Callbackpunkt übergeben
    protected void setUp(ArbeitsWocheCallbacks cb, ArbeitsWocheMainCallbacks cm){
        mCallback = cb;
        mCallbackMain = cm;
    }


    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        mContext = getContext();

        View view = inflater.inflate(R.layout.fragment_arbeitswoche, container, false);
        lZusatzwerte = view.findViewById(R.id.W_list_zusatzwerte);
        mAdapter_kopf =
                new ZusatzWertViewAdapter(ZusatzWertViewAdapter.VIEW_KOPF);
        GridLayoutManager layoutManger =
        new GridLayoutManager(
                mContext,
                1 );
        lZusatzwerte.setLayoutManager(layoutManger);
        lZusatzwerte.setAdapter(mAdapter_kopf);

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();

        // Einstellungen initialisieren
        ASettings.init(mContext, this::resume);
    }

    private void resume() {
        Bundle args = getArguments();
        Datum mKalender;
        if (args != null) {
            mKalender = new Datum(
                    args.getInt(ARG_JAHR),
                    args.getInt(ARG_MONAT),
                    args.getInt(ARG_TAG),
                    ASettings.aktJob.getWochenbeginn()
            );
        } else {
            mKalender = new Datum(ASettings.aktDatum.getDate(),
                    ASettings.aktJob.getWochenbeginn());
        }

        /*
         * das Aussehen der Oberfläche anpassen
         */
        View mInhalt = getView();
        if(mInhalt != null ) {
            mWoche = new Arbeitswoche(mKalender.getTimeInMillis(), ASettings.aktJob);

            RelativeLayout cDatum = mInhalt.findViewById(R.id.W_box_datum);
            cErgebnis = mInhalt.findViewById(R.id.W_box_ergebnis);
            tWoche = mInhalt.findViewById(R.id.W_wert_woche);
            tDatum = mInhalt.findViewById(R.id.W_wert_datum);
            tSoll = mInhalt.findViewById(R.id.W_wert_soll);
            tIst = mInhalt.findViewById(R.id.W_wert_ist);
            tDifferenz = mInhalt.findViewById(R.id.W_wert_diff);
            lTage = mInhalt.findViewById(R.id.W_liste_tage);

            // Sonstige Werte
            cSonstige = mInhalt.findViewById(R.id.W_box_sonstige);
            //lZusatzwerte = mInhalt.findViewById(R.id.W_list_zusatzwerte);
            LinearLayout cStundenlohn = mInhalt.findViewById(R.id.W_box_stundenlohn);
            tStundenlohn = mInhalt.findViewById(R.id.W_wert_Stundenlohn);

            iCompact = mInhalt.findViewById(R.id.W_icon_fold);
            ImageView iGoMonat = mInhalt.findViewById(R.id.W_go_monat);
            ImageView iCopyWoche = mInhalt.findViewById(R.id.W_copy_woche);

            iGoMonat.setOnClickListener(this);

            if(mWoche.getDatumLetzterTag().liegtVor(ASettings.letzterAnzeigeTag)) {
                iCopyWoche.setOnClickListener(this);
            } else {
                iCopyWoche.setVisibility(View.INVISIBLE);
            }

            // Farben des Kopfes setzen
            cDatum.setBackgroundColor(ASettings.aktJob.getFarbe_Tag());


            // Icon zum ein- und ausklappen der Zusammenfassung anpassen
            if (ASettings.res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                isCompact = ASettings.mPreferenzen.getBoolean(
                        ISettings.KEY_ANZEIGE_WOCHE_COMPACT, false);
                iCompact.setImageDrawable(
                        VectorDrawableCompat.create(
                                ASettings.res,
                                isCompact ?
                                        R.drawable.arrow_down :
                                        R.drawable.arrow_up,
                                mContext.getTheme())
                );
                //iCompact.setColorFilter(Color.WHITE);
                iCompact.setOnClickListener(this);
                cDatum.setOnClickListener(this);
                cErgebnis.setVisibility(isCompact ? View.GONE : View.VISIBLE);
            } else
                iCompact.setVisibility(View.GONE);

            if (!ASettings.isVerdienst)
                cStundenlohn.setVisibility(View.GONE);

            int anzahlTage =  mWoche.getTagzahl();
            if (anzahlTage > 0) {
                // Tagesliste erzeugen
                ArbeitstagExpandListAdapter aTage =
                        new ArbeitstagExpandListAdapter(
                                mContext,
                                mWoche.getTagListe(),
                                (ArbeitstagExpandListAdapter.ArbeitstagListeCallbacks) getActivity());
                lTage.setAdapter(aTage);
                // handler für das öffnen der Kindelemente, nur eins soll zur gleichen Zeit offen sein
                lTage.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
                    int previousGroup = -1;

                    @Override
                    public void onGroupExpand(int groupPosition) {
                        if (groupPosition != previousGroup)
                            lTage.collapseGroup(previousGroup);
                        previousGroup = groupPosition;
                    }
                });

                if (mKalender.get(Calendar.YEAR) == ASettings.aktDatum.get(Calendar.YEAR) &&
                        mKalender.get(Calendar.WEEK_OF_YEAR) == ASettings.aktDatum.get(Calendar.WEEK_OF_YEAR)) {
                    int pos;
                    anzahlTage -= 1;

                    if (ASettings.aktJob.isAnzeigeZukunft()) {
                        pos = ASettings.aktDatum.get(Calendar.DAY_OF_WEEK) - mKalender.getWochenbeginn();
                        if (pos < 0)
                            pos += 7;
                        if (ASettings.mPreferenzen.getBoolean(ISettings.KEY_ANZEIGE_UMG_SORT, false)) {
                            pos = anzahlTage - pos;
                        }
                    } else {
                        pos = ASettings.mPreferenzen.getBoolean(ISettings.KEY_ANZEIGE_UMG_SORT, false) ?
                                0 :
                                anzahlTage;
                    }
                    try {
                        lTage.setSelection(pos);

                        if (ASettings.mPreferenzen.getBoolean(ISettings.KEY_ANZEIGE_AKTTAG, true))
                            lTage.expandGroup(pos);
                    } catch (RuntimeException re) {
                        re.printStackTrace();
                    }
                }
            }
            //Statische Werte eintragen
            setDatum();
            //Dynamische Werte eintragen
            setBerechnung();
        }
    }

    // das Datum anzeigen
    private void setDatum(){
        tWoche.setText(getString(R.string.woche_nummer, mWoche.getNummer()));

        if(mWoche.getTagzahl() > 0) {
            tDatum.setText(
                    mWoche.getTag(0).getKalender().getString_Datum_Bereich(
                            mContext,
                            0,
                            mWoche.getTagzahl()-1,
                            Calendar.DAY_OF_WEEK
                    )
            );
        } else {
           tDatum.setText(
                    mWoche.getDatumErsterTag().getString_Datum_Bereich(
                            mContext,
                            0,
                            6,
                            Calendar.DAY_OF_WEEK
                    )
            );
        }
    }

    // die Berechnung der Stunden
    @SuppressLint("NotifyDataSetChanged")
    private void setBerechnung() {
        Uhrzeit mZeit = new Uhrzeit(mWoche.getSoll());

        tSoll.setText(mZeit.getStundenString(true, ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));

        mZeit.set(mWoche.getIst());
        tIst.setText(mZeit.getStundenString(true, ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));

        if (ASettings.isVerdienst)
            tStundenlohn.setText(ASettings.waehrungformat.format(mWoche.getVerdienst()));

        mZeit.set(mZeit.getAlsMinuten() - mWoche.getSoll());
        tDifferenz.setText(mZeit.getStundenString(false, ASettings.aktJob.isOptionSet(Arbeitsplatz.OPT_ANZEIGE_DEZIMAL)));
        if (mZeit.getAlsMinuten() == 0)
            tDifferenz.setTextColor(ASettings.aktJob.getFarbe_Schrift_default());
        else if (mZeit.getAlsMinuten() < 0)
            tDifferenz.setTextColor(ASettings.cNegativText);
        else
            tDifferenz.setTextColor(ASettings.cPositivText);

        // die Zusatzwerte anzeigen
        ZusatzWertListe mZusatzwerteSumme = new ZusatzWertListe(ASettings.aktJob.getZusatzfeldListe(), false);
        if (mZusatzwerteSumme.size() > 0) {
            for (Arbeitstag tag : mWoche.getTagListe()) {
                mZusatzwerteSumme.addListenWerte(tag.getTagZusatzwerte(IZusatzfeld.TEXT_NO));
            }
            mAdapter_kopf.setUp(
                    mZusatzwerteSumme.getListe(),
                    null);
            mAdapter_kopf.notifyDataSetChanged();
        } else
            cSonstige.setVisibility(View.GONE);

    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.W_box_datum || view.getId() == R.id.W_icon_fold) {
            SharedPreferences.Editor mEdit = ASettings.mPreferenzen.edit();
            isCompact = !isCompact;
            mEdit.putBoolean(ISettings.KEY_ANZEIGE_WOCHE_COMPACT, isCompact).apply();
            cErgebnis.setVisibility(isCompact ? View.GONE : View.VISIBLE);
            iCompact.setImageDrawable(
                    VectorDrawableCompat.create(
                            ASettings.res,
                            isCompact ?
                                    R.drawable.arrow_down :
                                    R.drawable.arrow_up,
                            mContext.getTheme())
            );
        } else if(view.getId() == R.id.W_go_monat){
            mCallbackMain.onArbeitswocheGoMonat(mWoche.getDatumErsterTag());
        } else if (view.getId() == R.id.W_copy_woche){
            PopupMenu popup = new PopupMenu(mContext, view);
            MenuInflater inflater = popup.getMenuInflater();
            inflater.inflate(R.menu.kopie_woche, popup.getMenu());
            popup.setOnMenuItemClickListener(this);
            popup.show();
        }
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) { int itemId = item.getItemId();
        if (itemId == R.id.kw_naechst) {
            // Kopie dieser Woche in der nächsten Woche anlegen
            mWoche.copy(1+ mWoche.getNummer());
            mCallback.onScrollWochen(1);
            return true;
        } else if (itemId == R.id.kw_uenaechst) {
            // Kopie dieser Woche in der nächsten Woche anlegen
            mWoche.copy(2+ mWoche.getNummer());
            mCallback.onScrollWochen(2);
            return true;
        } else {
            TextView tAnzahl;
            TextView tInterval;
            View dialogView = getLayoutInflater().inflate(R.layout.fragment_kopie_wochen, null);
            tAnzahl = dialogView.findViewById(R.id.kw_azahl);
            tInterval = dialogView.findViewById(R.id.kw_interval);
            ((TextView)dialogView.findViewById(R.id.kw_woche)).setText(getString(
                    R.string.dialog_wochen_woche,
                    mWoche.getNummer(),
                    mWoche.getDatumErsterTag().getString_Datum(mContext),
                    mWoche.getDatumLetzterTag().getString_Datum(mContext)
            ));
            AlertDialog.Builder copyDialog = new AlertDialog.Builder(mContext);
            copyDialog.setView(dialogView);
            copyDialog.setTitle(R.string.dialog_wochen_titel);
            copyDialog.setPositiveButton(R.string.picker_set, (d, which) -> {
                        assert getView() != null;
                        int anzahlKopien = Integer.parseInt(tAnzahl.getText().toString());
                        int interval = Integer.parseInt(tInterval.getText().toString());
                        int zielWoche = mWoche.getNummer();
                        for (int a = 0; a < anzahlKopien; a++) {
                            zielWoche += interval;
                            mWoche.copy(zielWoche);
                            mCallback.onScrollWochen(interval);
                        }
                    }).
                    setNegativeButton(R.string.picker_cancel, (d, which) -> {

                    });

            copyDialog.show();
            return true;
        }
    }

    // Callbacks zum Pager
    public interface ArbeitsWocheCallbacks {
        void onScrollWochen(int wochen);
    }

    // Callbacks zur Mainactivity
    public interface ArbeitsWocheMainCallbacks {
        void onArbeitswocheGoMonat(Datum datum);
    }
}
