package br.com.elotech.websaude.integracao.cnes.ui;

import br.com.elotech.websaude.integracao.cnes.backend.controller.UnidadeController;
import br.com.elotech.websaude.integracao.cnes.backend.controller.UsuariosController;
import br.com.elotech.websaude.integracao.cnes.backend.model.Estabelecimento;
import br.com.elotech.websaude.integracao.cnes.backend.model.Root;
import br.com.elotech.websaude.integracao.cnes.backend.model.dao.Conexao;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.ValoTheme;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import static br.com.elotech.websaude.integracao.cnes.backend.model.dao.Conexao.CONN;

@Title("Elotech - WebSocialSaúde Integração CNES")
@Theme("valo")
@SpringUI
public class MainUI extends UI {

    private static final long serialVersionUID = 1L;
    private static Root root;
    public static Grid<EstabelecimentoXML> grid = null;
    protected static List<EstabelecimentoXML> prestadores;
    private Label instrucoes;
    private CnesUploader cnesUploader = new CnesUploader();
    private     VerticalLayout layout = new VerticalLayout();
    private Button btnProcessar = new Button("Processar ...", VaadinIcons.ARROW_DOWN);
    private Label label = new Label("Bem Vindo ao Assistente de Importação do CNES!");
    private ProgressBar progresso = new ProgressBar();
    private Upload upload;
    private boolean status = false;

    @Override
    protected void init(VaadinRequest request) {

        Application.args = new String[]{
            request.getParameter("url"),    request.getParameter("u"), request.getParameter("s")
        };

        progresso.setVisible(false);
        progresso.setWidth(250, Unit.PIXELS);
        layout.addComponent(label);

        carregarUploadComponent();
        layout.addComponent(upload);
        layout.addComponent(progresso);
        instrucoes = new Label("<center>Ao aparecer a tabela, selecione a linha para obter a opção de editar o registro, <br/>"
                + "indicando se é ou não prestador determinada unidade, está opção estará disponível somente a primeira vez em que <br/>"
                + "executar o importador ou quando possuir novas unidades vínculadas. <br/>"
                + "Na próxima vez, que executar o mesmo não irá mais solicitar, carregando a opção desejada anteriormente automaticamente. <br/>"
                + "Este passo é obrigatório devido ao XML do CNES não exportar mais a informação sobre quem é ou não prestador. <br/>"
                + "O arquivo XML deve ser gerado por meio do programa desktop do CNES.</center>");
        layout.addComponent(instrucoes);
        instrucoes.setContentMode(ContentMode.HTML);
        layout.setComponentAlignment(instrucoes, Alignment.TOP_CENTER);
        layout.setComponentAlignment(upload, Alignment.TOP_CENTER);
        layout.setComponentAlignment(progresso, Alignment.TOP_CENTER);
        layout.setComponentAlignment(label, Alignment.TOP_CENTER);
        setContent(layout);

        btnProcessar.addClickListener(e -> {
            btnProcessarAction();
            if(MainUI.grid!=null) {
                layout.removeComponent(MainUI.grid);
            }
            layout.removeComponent(btnProcessar);
        });

    }

    private void carregarUploadComponent() {
        upload = new Upload("Upload do arquivo CNES XML", cnesUploader);
        upload.setStyleName(ValoTheme.BUTTON_TINY);
        upload.setIcon(VaadinIcons.UPLOAD);
        upload.setImmediateMode(true);

        JavaScript.getCurrent().execute("document.getElementsByClassName('gwt-FileUpload')[0].setAttribute('accept', '.XML')");
        carregarUploadEvents(upload);
    }

    private void carregarUploadEvents(Upload upload) {
        upload.addStartedListener(new Upload.StartedListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void uploadStarted(Upload.StartedEvent event) {
                upload.setVisible(false);
                progresso.setVisible(true);
                progresso.setCaption("Uploading em execução \"" + event.getFilename() + "\"");
            }
        });

        upload.addProgressListener(new Upload.ProgressListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void updateProgress(long readBytes, long contentLength) {
                progresso.setCaption("Tamanho: " + ((readBytes / contentLength) * 100) + "%");
            }

        });

        upload.addSucceededListener(new Upload.SucceededListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void uploadSucceeded(Upload.SucceededEvent event) {
                uploadExecutado(event);
            }

        });

        upload.addFailedListener(new Upload.FailedListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void uploadFailed(Upload.FailedEvent event) {
                progresso.setCaption("Uploading interrompido");
            }
        });

        upload.addFinishedListener(new Upload.FinishedListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void uploadFinished(Upload.FinishedEvent event) {
                upload.setVisible(true);
                upload.setCaption("Selecione outro arquivo");

            }
        });
    }

    private void uploadExecutado(Upload.SucceededEvent event) {
        progresso.setCaption("Upload \"" + event.getFilename() + "\" realizado");
        progresso.setValue(1);
        iniciarProcesso();
        if (status) {
            if(MainUI.grid!=null) {
                layout.addComponent(MainUI.grid);
                if(MainUI.grid.getHeaderRowCount()<1) {
                    btnProcessarAction();
                    if(MainUI.grid!=null)
                        layout.removeComponent(MainUI.grid);
                    layout.removeComponent(btnProcessar);
                }
            }
        } else {
            btnProcessarAction();
            if(MainUI.grid!=null)
                layout.removeComponent(MainUI.grid);
            layout.removeComponent(btnProcessar);
        }
    }

    public Grid createEhPrestador(List<EstabelecimentoXML> items) {
        if (items != null && !items.isEmpty()) {
                MainUI.grid = new Grid();
                MainUI.grid.setWidth(100, Unit.PERCENTAGE);
                MainUI.grid.setItems(items);
                status = true;
                Grid.Column column = MainUI.grid.addComponentColumn(
                        p -> new EloButton((p.ehPrestador?"Sim":"Não"),e-> {
                            p.setEhPrestador(!p.ehPrestador);
                            e.getButton().setCaption(p.ehPrestador?"Sim":"Não");
                        })
                );
                column.setCaption("Prestador?");
                MainUI.grid.addColumn(EstabelecimentoXML::getCnes).setCaption("CNES");
                MainUI.grid.addColumn(EstabelecimentoXML::getCnpj).setCaption("CNPJ");
                MainUI.grid.addColumn(EstabelecimentoXML::getNomeFantasia).setCaption("Nome Fantasia");
                MainUI.grid.addColumn(EstabelecimentoXML::getRazaoSocial).setCaption("Razão Social");
                MainUI.grid.setStyleName(ValoTheme.TABLE_SMALL);

                MainUI.grid.setFrozenColumnCount(1);
                MainUI.grid.getEditor().setEnabled(true);
                MainUI.grid.getEditor().setSaveCaption("Salvar");
                MainUI.grid.getEditor().setCancelCaption("Cancelar");
                MainUI.grid.getEditor().setBuffered(false);
                return MainUI.grid;
        }

        return null;
    }

    private void iniciarProcesso() {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
            Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
            Root config = (Root) jaxbUnmarshaller.unmarshal(CnesUploader.file);
            Conexao.abrirConexao(Application.args);
            MainUI.prestadores = preProcessar(config);
            MainUI.grid = createEhPrestador(prestadores);
            layout.addComponent(btnProcessar);
            layout.setComponentAlignment(btnProcessar, Alignment.TOP_CENTER);
            if (MainUI.grid != null) {
                layout.addComponent(MainUI.grid);
            }
            Conexao.fecharConexao();

        } catch (Exception ex) {
            Conexao.fecharConexao();
            Logger.getLogger(MainUI.class.getName()).log(Level.SEVERE, null, ex);
            Notification.show("Ocorreu um erro!", "Por favor, contacte o suporte para reportar.\n" + ex.getMessage(), Notification.Type.ERROR_MESSAGE);
        }
        if(CnesUploader.file.exists()){
            CnesUploader.file.delete();
        }

    }

    private static void processar(Root root) throws SQLException {

        if (root != null) {

            UsuariosController usuariosController = new UsuariosController();
            usuariosController.inativarUsuarios();
            UnidadeController estabelecimentoController = new UnidadeController();

            List<Estabelecimento> prestadores = new ArrayList();
            if (MainUI.prestadores != null) {
                for (EstabelecimentoXML exml : MainUI.prestadores) {
                    if (exml.isEhPrestador()) {
                        prestadores.add(exml.e);
                    }
                }

                prestadores.addAll(estabelecimentoController.dadosPrestadoresExistentes(MainUI.root.estabelecimentos));

                estabelecimentoController.dadosGeraisEstabelecimentos(root.estabelecimentos, prestadores);
                usuariosController.dadosProfissionais(MainUI.root.estabelecimentos, prestadores, 0);

            } else {
                Notification.show("Arquivo XML Inválido ou Não possuí Dados!", Notification.Type.ERROR_MESSAGE);
            }

        }
    }

    private static List<EstabelecimentoXML> preProcessar(Root root) throws SQLException {
        if (root != null) {
            UnidadeController estabelecimentoController = new UnidadeController();
            MainUI.root = root;
            return estabelecimentoController.dadosEstabelecimentoXML(root.estabelecimentos);
        }

        return new ArrayList<>();
    }

    private void btnProcessarAction() {

        try {
            Conexao.abrirConexao(Application.args);
            processar(root);
            CONN.commit();
            Notification.show("Importação realizada com sucesso!", Notification.Type.TRAY_NOTIFICATION);

            if (grid != null) {
                layout.removeComponent(grid);
            }
            layout.removeComponent(btnProcessar);

        } catch (SQLException ex) {
            Notification.show("Ocorreu um erro!", "Por favor, contacte o suporte para reportar.\n" + ex.getMessage(), Notification.Type.ERROR_MESSAGE);
            Logger.getLogger(MainUI.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Conexao.fecharConexao();
        }

        layout.addComponent(btnProcessar);
        layout.setComponentAlignment(btnProcessar, Alignment.TOP_CENTER);
        if(MainUI.grid!=null)
            layout.addComponent(MainUI.grid);

        upload.setVisible(false);
        instrucoes.setValue("Processo Concluído!");
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MainUI)) return false;
        if (!super.equals(o)) return false;
        MainUI that = (MainUI) o;
        if (instrucoes != null ? !instrucoes.equals(that.instrucoes) : that.instrucoes != null) return false;
        return upload != null ? upload.equals(that.upload) : that.upload == null;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + (instrucoes != null ? instrucoes.hashCode() : 0);
        result = 31 * result + (cnesUploader != null ? cnesUploader.hashCode() : 0);
        result = 31 * result + (layout != null ? layout.hashCode() : 0);
        result = 31 * result + (btnProcessar != null ? btnProcessar.hashCode() : 0);
        result = 31 * result + (label != null ? label.hashCode() : 0);
        result = 31 * result + (progresso != null ? progresso.hashCode() : 0);
        result = 31 * result + (upload != null ? upload.hashCode() : 0);
        result = 31 * result + (status ? 1 : 0);
        return result;
    }
}
