package cn.ppdxzz.service.impl;

import cn.ppdxzz.dao.VisitorDao;
import cn.ppdxzz.domain.Visitor;
import cn.ppdxzz.poi.WriteExcel;
import cn.ppdxzz.service.VisitorService;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Description:访客服务实现类，实现了VisitorService接口定义的方法
 * 该类作为业务逻辑层的具体实现，负责调用数据访问层（VisitorDao）的方法来完成与访客相关的各项业务操作，
 * 同时利用一些工具类（如PageHelper进行分页，WriteExcel进行Excel文件导出等）来处理更复杂的业务逻辑。
 *
 * @Date: 2020/2/18 18:50
 * @Author: PeiChen
 */
// 使用 @Service 注解将该类标记为Spring框架中的服务层组件，并指定了组件的名称为 "visitorService"，方便在依赖注入时使用
@Service("visitorService")
public class VisitorServiceImpl implements VisitorService {

    // 定义一个VisitorDao类型的成员变量，用于后续调用数据访问层的方法来操作数据库中的访客数据
    private VisitorDao visitorDao;

    /**
     * 通过Autowired注解自动注入VisitorDao
     * @Autowired注解用于告诉Spring框架自动装配VisitorDao的实例到该成员变量中，
     * 通过类型匹配找到对应的实现类并注入，使得本类可以方便地调用数据访问层的方法。
     * @param visitorDao 访客数据访问对象，该参数接收Spring框架注入的VisitorDao的实例。
     */
    @Autowired
    public void setVisitorDao(VisitorDao visitorDao) {
        this.visitorDao = visitorDao;
    }

    /**
     * 登记到访信息
     * 实现VisitorService接口中定义的添加访客信息的方法，该方法接收一个Visitor对象作为参数，
     * 通过调用VisitorDao的对应方法将访客信息持久化存储到数据库中。
     *
     * @param visitor 访客对象，包含访客的详细信息，如姓名、学号、联系方式、访问地址等，这些信息将被保存到数据库中对应的访客记录里。
     * @throws Exception 如果添加过程中发生错误，例如数据库连接异常、插入数据违反约束等情况，则抛出异常，由调用该方法的上层代码进行处理。
     */
    @Override
    public void add(Visitor visitor) throws Exception {
        // 调用VisitorDao的add方法，将传入的访客对象visitor的信息插入到数据库中，实现来访登记功能，将访客信息持久化
        visitorDao.add(visitor);
    }

    /**
     * 按时间晚的优先显示查询所有访客记录，并分页显示
     * 实现VisitorService接口中定义的查询所有访客记录的方法，该方法支持分页功能，按照来访时间降序排列查询结果，
     * 先利用PageHelper插件设置分页参数，然后调用VisitorDao的方法从数据库中获取访客记录列表。
     *
     * @return 包含访客记录的列表，返回的列表中的元素为Visitor对象，每个对象代表一条访客记录，包含了访客的各项详细信息。
     * @throws Exception 如果查询过程中发生错误，比如数据库查询语句执行失败、分页设置出现问题等，则抛出异常，由调用者负责处理。
     */
    @Override
    public List<Visitor> findAll(int page, int size) throws Exception {
        // 使用PageHelper插件进行分页，传入当前页码page和每页显示的记录数size参数，该插件会自动拦截后续的数据库查询操作，
        // 根据设置的分页参数对查询结果进行分页处理，使得返回的结果是符合分页要求的访客记录列表
        PageHelper.startPage(page, size);
        // 调用VisitorDao的findAll方法，从数据库中查询所有访客记录，由于前面已经设置了分页，这里返回的结果将是分页后的访客记录列表，
        // 按照来访时间降序排列（由VisitorDao的findAll方法中的SQL语句决定排序方式）
        return visitorDao.findAll();
    }

    /**
     * 根据关键字模糊查询访客记录，并按时间倒序排列，然后分页显示
     * 实现VisitorService接口中定义的根据关键字进行模糊查询访客记录的方法，支持分页功能，按照来访时间降序排列查询结果，
     * 先利用PageHelper插件设置分页参数，然后调用VisitorDao的对应方法从数据库中获取符合关键字模糊匹配的访客记录列表。
     *
     * @param page 当前页码，用于指定要获取第几页的数据，通过该参数结合每页显示记录数可以确定具体的分页查询范围。
     * @param size 每页显示的记录数，用于控制每页展示多少条符合条件的访客记录，通过和当前页码配合实现分页查询功能。
     * @param keyword 搜索关键字，是一个字符串类型的值，用于在访客记录的多个字段（如姓名、学号等）中进行模糊匹配查找符合条件的记录。
     * @return 包含搜索结果的访客记录列表，返回的列表中的元素为Visitor对象，每个对象代表一条符合模糊查询条件的访客记录，包含了访客的各项详细信息。
     * @throws Exception 如果搜索过程中发生错误，例如数据库查询语法错误、分页参数设置不合理等情况，则抛出异常，由调用该方法的上层代码进行处理。
     */
    @Override
    public List<Visitor> search(int page, int size, String keyword) throws Exception {
        // 使用PageHelper插件进行分页，传入当前页码page和每页显示的记录数size参数，让插件为后续的数据库查询操作添加分页逻辑，
        // 确保返回符合分页要求的查询结果
        PageHelper.startPage(page, size);
        // 调用VisitorDao的search方法，传入搜索关键字keyword，从数据库中查询所有符合关键字模糊匹配条件的访客记录，
        // 并且按照来访时间降序排列（由VisitorDao的search方法中的SQL语句决定排序方式），最终返回分页后的符合条件的访客记录列表
        return visitorDao.search(keyword);
    }

    /**
     * 访客离开后修改离开时间（访客注销）
     * 实现VisitorService接口中定义的用于注销访客记录的方法，该方法接收访客的唯一标识符和离开时间作为参数，
     * 通过调用VisitorDao的对应方法更新数据库中访客记录的离开时间字段，完成访客注销的业务逻辑。
     *
     * @param id 访客的唯一标识符，用于在数据库中准确找到对应的访客记录，一般是一个唯一的字符串值（如UUID），与数据库表中的主键对应。
     * @param end_date 访客的离开时间，是一个表示日期时间的字符串，格式通常与数据库中存储时间的格式一致（如 yyyy-MM-dd HH:mm:ss），
     *                 该值将被更新到数据库中对应访客记录的离开时间字段，用于记录访客离开的时间点。
     * @throws Exception 如果更新过程中发生错误，比如数据库连接异常、更新语句执行失败等情况，则抛出异常，由调用该方法的上层代码进行处理。
     */
    @Override
    public void logout(String id, String end_date) throws Exception {
        // 调用VisitorDao的logout方法，传入访客的唯一标识符id和离开时间end_date，在数据库中执行更新操作，
        // 将对应访客记录的离开时间字段更新为传入的end_date值，实现访客记录的注销功能，即标记访客已经离开
        visitorDao.logout(id, end_date);
    }

    /**
     * 导出访客记录到Excel文件
     * 实现VisitorService接口中定义的导出访客记录为Excel文件的方法，该方法通过从数据库中获取所有访客记录，
     * 整理数据格式后利用WriteExcel类将数据写入Excel文件，并返回该Excel文件对应的输入流，以便后续在控制器中通过响应流发送给客户端进行下载。
     *
     * @return 访客记录的输入流，返回的输入流指向包含访客记录数据的Excel文件内容，可通过该输入流将Excel文件发送给客户端，
     *         实现访客记录的导出功能，客户端可以将接收到的输入流保存为本地的Excel文件进行查看和分析。
     * @throws Exception 如果导出过程中发生错误，例如读取数据库数据失败、写入Excel文件出现问题、生成输入流异常等情况，则抛出异常，
     *                   由调用该方法的上层代码（如控制器层）进行处理。
     */
    @Override
    public InputStream getInputStream() throws Exception {
        // Excel中的每列列名，依次对应数据库的字段，定义一个字符串数组，用于指定要导出到Excel文件中的列标题，
        // 这些标题与数据库中访客表的字段名相对应，方便在Excel文件中清晰展示访客记录的各项信息
        String[] title = new String[]{"ID", "姓名", "学号", "联系方式", "访问地址", "来访时间", "离开时间", "来访原因"};
        // 调用VisitorDao的findAll方法，从数据库中获取所有访客记录，得到一个包含所有访客信息的列表，后续将基于这些数据来填充Excel文件内容
        List<Visitor> visitors = visitorDao.findAll();
        // 创建一个List<Object[]>类型的列表，用于存储整理后的访客数据，每个Object[]数组代表一行数据，
        // 数组中的元素依次对应Excel文件中的每列数据（与前面定义的title列名顺序对应），方便后续将数据批量写入Excel文件
        List<Object[]> datalist = new ArrayList<>();
        // 遍历从数据库中获取到的所有访客记录列表visitors，将每条访客记录的数据按照指定顺序整理到Object[]数组中，并添加到datalist列表中
        for (int i = 0; i < visitors.size(); i++) {
            Object[] obj = new Object[8];
            obj[0] = visitors.get(i).getId();
            obj[1] = visitors.get(i).getName();
            obj[2] = visitors.get(i).getSno();
            obj[3] = visitors.get(i).getPhone();
            obj[4] = visitors.get(i).getPlace();
            obj[5] = visitors.get(i).getBegin_date();
            obj[6] = visitors.get(i).getEnd_date();
            obj[7] = visitors.get(i).getVisit_result();
            datalist.add(obj);
        }
        // 使用WriteExcel类将数据写入Excel文件，创建一个WriteExcel类的实例，传入列标题title和整理好的数据列表datalist，
        // 该类内部会实现将数据按照指定格式写入到Excel文件的逻辑，并返回该Excel文件对应的输入流
        WriteExcel excel = new WriteExcel(title, datalist);
        // 调用WriteExcel类实例的export方法，获取包含访客记录数据的Excel文件的输入流，以便后续在控制器层将该输入流通过响应流发送给客户端，
        // 实现访客记录的导出功能，客户端可以将接收到的输入流保存为本地的Excel文件进行查看和分析
        return excel.export();
    }

    /**
     * 获取访客日志记录，并分页显示
     * 实现VisitorService接口中定义的获取访客日志记录的方法，该方法支持分页功能，按照来访时间降序排列查询结果，
     * 先利用PageHelper插件设置分页参数，然后调用VisitorDao的方法从数据库中获取访客日志记录列表。
     *
     * @param page 当前页码，用于指定要获取第几页的访客日志记录数据，通过该参数结合每页显示记录数可以确定具体的分页查询范围。
     * @param size 每页显示的记录数，用于控制每页展示多少条访客日志记录，通过和当前页码配合实现分页查询功能。
     * @return 包含访客日志记录的列表，返回的列表中的元素为Visitor对象，每个对象代表一条访客日志记录，包含了访客的各项详细信息，
     *         例如来访时间、离开时间、来访原因等，用于展示访客的访问历史记录情况。
     * @throws Exception 如果获取日志记录过程中发生错误，比如数据库查询语句执行失败、分页设置出现问题等情况，则抛出异常，由调用该方法的上层代码进行处理。
     */
    @Override
    public List<Visitor> log(int page, int size) throws Exception {
        // 使用PageHelper插件进行分页，传入当前页码page和每页显示的记录数size参数，该插件会自动拦截后续的数据库查询操作，
        // 根据设置的分页参数对查询结果进行分页处理，使得返回的结果是符合分页要求的访客日志记录列表
        PageHelper.startPage(page, size);
        // 调用VisitorDao的findAll方法，从数据库中查询所有访客日志记录，由于前面已经设置了分页，这里返回的结果将是分页后的访客日志记录列表，
        // 按照来访时间降序排列（由VisitorDao的findAll方法中的SQL语句决定排序方式）
        return visitorDao.findAll();
    }
}