"""
Import/Export routes for data migration and GDPR compliance
"""

import json
import os
from datetime import datetime, timedelta

from flask import Blueprint, current_app, jsonify, render_template, request, send_file
from flask_login import current_user, login_required
from werkzeug.utils import secure_filename

from app import db
from app.models import DataExport, DataImport, User
from app.utils.backup import restore_backup as restore_backup_archive
from app.utils.data_export import create_backup, export_filtered_data, export_user_data_gdpr
from app.utils.data_import import ImportError as DataImportError
from app.utils.data_import import (
    import_csv_clients,
    import_csv_time_entries,
    import_from_harvest,
    import_from_toggl,
    restore_from_backup,
)
from app.utils.module_helpers import module_enabled

import_export_bp = Blueprint("import_export", __name__)


# ============================================================================
# Import Routes
# ============================================================================


@import_export_bp.route("/import-export")
@login_required
@module_enabled("import_export")
def import_export_page():
    """Render the import/export page"""
    return render_template("import_export/index.html")


@import_export_bp.route("/api/import/csv", methods=["POST"])
@login_required
@module_enabled("import_export")
def import_csv():
    """
    Import time entries from CSV file

    Expected multipart/form-data with 'file' field
    """
    if "file" not in request.files:
        return jsonify({"error": "No file provided"}), 400

    file = request.files["file"]

    if file.filename == "":
        return jsonify({"error": "No file selected"}), 400

    if not file.filename.endswith(".csv"):
        return jsonify({"error": "File must be a CSV"}), 400

    try:
        # Read file content
        csv_content = file.read().decode("utf-8")

        # Create import record
        import_record = DataImport(
            user_id=current_user.id, import_type="csv", source_file=secure_filename(file.filename)
        )
        db.session.add(import_record)
        db.session.commit()

        # Perform import
        summary = import_csv_time_entries(user_id=current_user.id, csv_content=csv_content, import_record=import_record)

        return jsonify({"success": True, "import_id": import_record.id, "summary": summary}), 200

    except DataImportError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        current_app.logger.error(f"CSV import error: {str(e)}")
        return jsonify({"error": "Import failed. Please check the file format."}), 500


@import_export_bp.route("/api/import/toggl", methods=["POST"])
@login_required
@module_enabled("import_export")
def import_toggl():
    """
    Import time entries from Toggl Track

    Expected JSON body:
    {
        "api_token": "...",
        "workspace_id": "...",
        "start_date": "2024-01-01",
        "end_date": "2024-12-31"
    }
    """
    data = request.get_json()

    if not data:
        return jsonify({"error": "No data provided"}), 400

    api_token = data.get("api_token")
    workspace_id = data.get("workspace_id")
    start_date_str = data.get("start_date")
    end_date_str = data.get("end_date")

    if not all([api_token, workspace_id, start_date_str, end_date_str]):
        return jsonify({"error": "Missing required fields"}), 400

    try:
        # Parse dates
        start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
        end_date = datetime.strptime(end_date_str, "%Y-%m-%d")

        # Create import record
        import_record = DataImport(
            user_id=current_user.id, import_type="toggl", source_file=f"Toggl Workspace {workspace_id}"
        )
        db.session.add(import_record)
        db.session.commit()

        # Perform import
        summary = import_from_toggl(
            user_id=current_user.id,
            api_token=api_token,
            workspace_id=workspace_id,
            start_date=start_date,
            end_date=end_date,
            import_record=import_record,
        )

        return jsonify({"success": True, "import_id": import_record.id, "summary": summary}), 200

    except DataImportError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        current_app.logger.error(f"Toggl import error: {str(e)}")
        return jsonify({"error": "Import failed. Please check your credentials and try again."}), 500


@import_export_bp.route("/api/import/harvest", methods=["POST"])
@login_required
@module_enabled("import_export")
def import_harvest():
    """
    Import time entries from Harvest

    Expected JSON body:
    {
        "account_id": "...",
        "api_token": "...",
        "start_date": "2024-01-01",
        "end_date": "2024-12-31"
    }
    """
    data = request.get_json()

    if not data:
        return jsonify({"error": "No data provided"}), 400

    account_id = data.get("account_id")
    api_token = data.get("api_token")
    start_date_str = data.get("start_date")
    end_date_str = data.get("end_date")

    if not all([account_id, api_token, start_date_str, end_date_str]):
        return jsonify({"error": "Missing required fields"}), 400

    try:
        # Parse dates
        start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
        end_date = datetime.strptime(end_date_str, "%Y-%m-%d")

        # Create import record
        import_record = DataImport(
            user_id=current_user.id, import_type="harvest", source_file=f"Harvest Account {account_id}"
        )
        db.session.add(import_record)
        db.session.commit()

        # Perform import
        summary = import_from_harvest(
            user_id=current_user.id,
            account_id=account_id,
            api_token=api_token,
            start_date=start_date,
            end_date=end_date,
            import_record=import_record,
        )

        return jsonify({"success": True, "import_id": import_record.id, "summary": summary}), 200

    except DataImportError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        current_app.logger.error(f"Harvest import error: {str(e)}")
        return jsonify({"error": "Import failed. Please check your credentials and try again."}), 500


@import_export_bp.route("/api/import/status/<int:import_id>")
@login_required
@module_enabled("import_export")
def import_status(import_id):
    """Get status of an import operation"""
    import_record = DataImport.query.get_or_404(import_id)

    # Check permissions
    if not current_user.is_admin and import_record.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    return jsonify(import_record.to_dict()), 200


@import_export_bp.route("/api/import/history")
@login_required
@module_enabled("import_export")
def import_history():
    """Get import history for current user"""
    if current_user.is_admin:
        imports = DataImport.query.order_by(DataImport.started_at.desc()).limit(50).all()
    else:
        imports = (
            DataImport.query.filter_by(user_id=current_user.id).order_by(DataImport.started_at.desc()).limit(50).all()
        )

    return jsonify({"imports": [imp.to_dict() for imp in imports]}), 200


# ============================================================================
# Export Routes
# ============================================================================


@import_export_bp.route("/api/export/gdpr", methods=["POST"])
@login_required
@module_enabled("import_export")
def export_gdpr():
    """
    Export all user data for GDPR compliance

    Expected JSON body:
    {
        "format": "json" | "zip"
    }
    """
    data = request.get_json() or {}
    export_format = data.get("format", "json")

    if export_format not in ["json", "zip"]:
        return jsonify({"error": 'Invalid format. Use "json" or "zip"'}), 400

    try:
        # Create export record
        export_record = DataExport(user_id=current_user.id, export_type="gdpr", export_format=export_format)
        db.session.add(export_record)
        db.session.commit()

        export_record.start_processing()

        # Perform export
        result = export_user_data_gdpr(user_id=current_user.id, export_format=export_format)

        export_record.complete(
            file_path=result["filepath"], file_size=result["file_size"], record_count=result["record_count"]
        )

        return (
            jsonify(
                {
                    "success": True,
                    "export_id": export_record.id,
                    "filename": result["filename"],
                    "download_url": f"/api/export/download/{export_record.id}",
                }
            ),
            200,
        )

    except Exception as e:
        current_app.logger.error(f"GDPR export error: {str(e)}")
        if "export_record" in locals():
            export_record.fail(str(e))
        return jsonify({"error": "Export failed. Please try again."}), 500


@import_export_bp.route("/api/export/filtered", methods=["POST"])
@login_required
@module_enabled("import_export")
def export_filtered():
    """
    Export filtered data

    Expected JSON body:
    {
        "format": "json" | "csv",
        "filters": {
            "include_time_entries": true,
            "include_projects": false,
            "include_expenses": true,
            "start_date": "2024-01-01",
            "end_date": "2024-12-31",
            "project_id": null,
            "billable_only": false
        }
    }
    """
    data = request.get_json()

    if not data:
        return jsonify({"error": "No data provided"}), 400

    export_format = data.get("format", "json")
    filters = data.get("filters", {})

    if export_format not in ["json", "csv"]:
        return jsonify({"error": 'Invalid format. Use "json" or "csv"'}), 400

    try:
        # Create export record
        export_record = DataExport(
            user_id=current_user.id, export_type="filtered", export_format=export_format, filters=filters
        )
        db.session.add(export_record)
        db.session.commit()

        export_record.start_processing()

        # Perform export
        result = export_filtered_data(user_id=current_user.id, filters=filters, export_format=export_format)

        export_record.complete(
            file_path=result["filepath"], file_size=result["file_size"], record_count=result["record_count"]
        )

        return (
            jsonify(
                {
                    "success": True,
                    "export_id": export_record.id,
                    "filename": result["filename"],
                    "download_url": f"/api/export/download/{export_record.id}",
                }
            ),
            200,
        )

    except Exception as e:
        current_app.logger.error(f"Filtered export error: {str(e)}")
        if "export_record" in locals():
            export_record.fail(str(e))
        return jsonify({"error": "Export failed. Please try again."}), 500


@import_export_bp.route("/api/export/backup", methods=["POST"])
@login_required
@module_enabled("import_export")
def export_backup():
    """
    Create a full database backup (admin only)
    """
    if not current_user.is_admin:
        return jsonify({"error": "Admin access required"}), 403

    try:
        # Create export record
        export_record = DataExport(user_id=current_user.id, export_type="backup", export_format="json")
        db.session.add(export_record)
        db.session.commit()

        export_record.start_processing()

        # Create backup
        result = create_backup(user_id=current_user.id)

        export_record.complete(
            file_path=result["filepath"], file_size=result["file_size"], record_count=result["record_count"]
        )

        return (
            jsonify(
                {
                    "success": True,
                    "export_id": export_record.id,
                    "filename": result["filename"],
                    "download_url": f"/api/export/download/{export_record.id}",
                }
            ),
            200,
        )

    except Exception as e:
        current_app.logger.error(f"Backup creation error: {str(e)}")
        if "export_record" in locals():
            export_record.fail(str(e))
        return jsonify({"error": "Backup failed. Please try again."}), 500


@import_export_bp.route("/api/export/download/<int:export_id>")
@login_required
@module_enabled("import_export")
def download_export(export_id):
    """Download an export file"""
    export_record = DataExport.query.get_or_404(export_id)

    # Check permissions
    if not current_user.is_admin and export_record.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    # Check if export is complete
    if export_record.status != "completed":
        return jsonify({"error": "Export is not ready yet"}), 400

    # Check if file exists
    if not export_record.file_path or not os.path.exists(export_record.file_path):
        return jsonify({"error": "Export file not found"}), 404

    # Check if expired
    if export_record.is_expired():
        return jsonify({"error": "Export has expired"}), 410

    return send_file(
        export_record.file_path, as_attachment=True, download_name=os.path.basename(export_record.file_path)
    )


@import_export_bp.route("/api/export/status/<int:export_id>")
@login_required
@module_enabled("import_export")
def export_status(export_id):
    """Get status of an export operation"""
    export_record = DataExport.query.get_or_404(export_id)

    # Check permissions
    if not current_user.is_admin and export_record.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    return jsonify(export_record.to_dict()), 200


@import_export_bp.route("/api/export/history")
@login_required
@module_enabled("import_export")
def export_history():
    """Get export history for current user"""
    if current_user.is_admin:
        exports = DataExport.query.order_by(DataExport.created_at.desc()).limit(50).all()
    else:
        exports = (
            DataExport.query.filter_by(user_id=current_user.id).order_by(DataExport.created_at.desc()).limit(50).all()
        )

    return jsonify({"exports": [exp.to_dict() for exp in exports]}), 200


# ============================================================================
# Backup/Restore Routes
# ============================================================================


@import_export_bp.route("/api/backup/restore", methods=["POST"])
@login_required
@module_enabled("import_export")
def restore_backup():
    """
    Restore from backup file (admin only)

    Expected multipart/form-data with 'file' field
    """
    if not current_user.is_admin:
        return jsonify({"error": "Admin access required"}), 403

    if "file" not in request.files:
        return jsonify({"error": "No file provided"}), 400

    file = request.files["file"]

    if file.filename == "":
        return jsonify({"error": "No file selected"}), 400

    fn_lower = (file.filename or "").lower()
    if not (fn_lower.endswith(".json") or fn_lower.endswith(".zip")):
        return jsonify({"error": "File must be a JSON or ZIP backup file"}), 400

    filepath = None
    try:
        # Save uploaded file temporarily
        backup_dir = os.path.join(current_app.config.get("UPLOAD_FOLDER", "/data/uploads"), "backups")
        os.makedirs(backup_dir, exist_ok=True)

        filename = secure_filename(file.filename)
        filepath = os.path.join(backup_dir, f"restore_{filename}")
        file.save(filepath)

        is_zip = fn_lower.endswith(".zip")

        if is_zip:
            # Full system backup (same as Admin restore)
            app_obj = current_app._get_current_object()
            success, message = restore_backup_archive(app_obj, filepath)
            if not success:
                return jsonify({"error": message}), 400
            return (
                jsonify(
                    {
                        "success": True,
                        "import_id": None,
                        "statistics": {"message": message},
                        "message": "Backup restored successfully",
                    }
                ),
                200,
            )
        else:
            # JSON backup (Import/Export style)
            import_record = DataImport(user_id=current_user.id, import_type="backup", source_file=filename)
            db.session.add(import_record)
            db.session.commit()

            statistics = restore_from_backup(user_id=current_user.id, backup_file_path=filepath)

            return (
                jsonify(
                    {
                        "success": True,
                        "import_id": import_record.id,
                        "statistics": statistics,
                        "message": "Backup restored successfully",
                    }
                ),
                200,
            )

    except DataImportError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        current_app.logger.error(f"Backup restore error: {str(e)}")
        return jsonify({"error": "Restore failed. Please check the backup file."}), 500
    finally:
        if filepath and os.path.exists(filepath):
            try:
                os.remove(filepath)
            except OSError:
                pass


# ============================================================================
# Migration Wizard Routes
# ============================================================================


@import_export_bp.route("/api/migration/wizard/start", methods=["POST"])
@login_required
@module_enabled("import_export")
def start_migration_wizard():
    """
    Start the migration wizard

    Expected JSON body:
    {
        "source": "toggl" | "harvest" | "csv",
        "credentials": {...},
        "options": {...}
    }
    """
    data = request.get_json()

    if not data:
        return jsonify({"error": "No data provided"}), 400

    source = data.get("source")

    if source not in ["toggl", "harvest", "csv"]:
        return jsonify({"error": "Invalid source"}), 400

    # Store wizard state in session or return wizard ID
    wizard_id = f"wizard_{current_user.id}_{datetime.utcnow().timestamp()}"

    return (
        jsonify(
            {
                "success": True,
                "wizard_id": wizard_id,
                "next_step": "credentials",
                "message": f"Migration wizard started for {source}",
            }
        ),
        200,
    )


@import_export_bp.route("/api/migration/wizard/<wizard_id>/preview", methods=["POST"])
@login_required
@module_enabled("import_export")
def preview_migration(wizard_id):
    """
    Preview data before importing

    This would fetch a small sample of data to show the user what will be imported
    """
    data = request.get_json()

    # Implementation would depend on the source
    # For now, return a mock preview

    return jsonify({"success": True, "preview": {"sample_entries": [], "total_count": 0, "date_range": {}}}), 200


@import_export_bp.route("/api/migration/wizard/<wizard_id>/execute", methods=["POST"])
@login_required
@module_enabled("import_export")
def execute_migration(wizard_id):
    """
    Execute the migration after preview
    """
    data = request.get_json()

    # This would trigger the actual import based on the wizard configuration

    return jsonify({"success": True, "message": "Migration started", "import_id": None}), 200


# ============================================================================
# Template Endpoints
# ============================================================================


@import_export_bp.route("/api/import/csv/clients", methods=["POST"])
@login_required
@module_enabled("import_export")
def import_csv_clients_route():
    """
    Import clients from CSV file

    Expected multipart/form-data with 'file' field
    Optional query parameters:
        - skip_duplicates (default: true): Whether to skip duplicate clients
        - duplicate_detection_fields: Comma-separated list of fields to use for duplicate detection.
          Can include 'name' for client name, or custom field names (e.g., 'debtor_number').
          Examples: "debtor_number", "name,debtor_number", "erp_id"
          If not provided, defaults to checking by name and all custom fields found in CSV.
    """
    try:
        if "file" not in request.files:
            return jsonify({"error": "No file provided"}), 400

        file = request.files["file"]

        if file.filename == "":
            return jsonify({"error": "No file selected"}), 400

        if not file.filename.endswith(".csv"):
            return jsonify({"error": "File must be a CSV"}), 400

        skip_duplicates = request.args.get("skip_duplicates", "true").lower() == "true"

        # Parse duplicate detection fields
        duplicate_detection_fields = None
        duplicate_fields_param = request.args.get("duplicate_detection_fields", "").strip()
        if duplicate_fields_param:
            # Support comma-separated list: "debtor_number,erp_id" or "name,debtor_number"
            duplicate_detection_fields = [field.strip() for field in duplicate_fields_param.split(",") if field.strip()]

        # Read file content
        file_bytes = file.read()
        try:
            csv_content = file_bytes.decode("utf-8")
        except UnicodeDecodeError:
            # Try with different encodings
            try:
                csv_content = file_bytes.decode("latin-1")
            except Exception:
                return (
                    jsonify({"error": "Could not decode file. Please ensure it's a valid UTF-8 or Latin-1 CSV file."}),
                    400,
                )

        if not csv_content or not csv_content.strip():
            return jsonify({"error": "File is empty"}), 400

        # Create import record
        import_record = None
        try:
            import_record = DataImport(
                user_id=current_user.id, import_type="csv_clients", source_file=secure_filename(file.filename)
            )
            db.session.add(import_record)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(f"Failed to create import record: {str(e)}")
            db.session.rollback()
            return jsonify({"error": f"Failed to initialize import: {str(e)}"}), 500

        # Perform import
        try:
            summary = import_csv_clients(
                user_id=current_user.id,
                csv_content=csv_content,
                import_record=import_record,
                skip_duplicates=skip_duplicates,
                duplicate_detection_fields=duplicate_detection_fields,
            )
            response = jsonify({"success": True, "import_id": import_record.id, "summary": summary})
            response.headers["Content-Type"] = "application/json"
            return response, 200
        except DataImportError as e:
            current_app.logger.error(f"DataImportError in client import: {str(e)}")
            if import_record:
                try:
                    import_record.fail(str(e))
                    db.session.commit()
                except Exception as db_error:
                    db.session.rollback()
                    current_app.logger.error(f"Failed to update import record status: {db_error}")
            return jsonify({"error": str(e)}), 400
        except Exception as e:
            current_app.logger.exception(f"Unexpected error in client import: {str(e)}")
            if import_record:
                try:
                    import_record.fail(f"Unexpected error: {str(e)}")
                    db.session.commit()
                except Exception as db_error:
                    db.session.rollback()
                    current_app.logger.error(f"Failed to update import record status: {db_error}")
            # Return detailed error in debug mode, generic in production
            error_msg = (
                str(e)
                if current_app.config.get("FLASK_DEBUG")
                else "Import failed. Please check the file format and try again."
            )
            return jsonify({"error": error_msg}), 500

    except Exception as e:
        current_app.logger.exception(f"Top-level error in client import route: {str(e)}")
        error_msg = (
            str(e) if current_app.config.get("FLASK_DEBUG") else "An unexpected error occurred. Please try again."
        )
        return jsonify({"error": error_msg}), 500


@import_export_bp.route("/api/import/template/csv")
@login_required
@module_enabled("import_export")
def download_csv_template():
    """Download CSV import template for time entries"""
    template_content = """project_name,client_name,task_name,start_time,end_time,duration_hours,notes,tags,billable
Example Project,Example Client,Example Task,2024-01-01 09:00:00,2024-01-01 10:30:00,1.5,Meeting with client,meeting;client,true
Another Project,Another Client,,2024-01-01 14:00:00,2024-01-01 16:00:00,2.0,Development work,dev;coding,true
"""

    from io import BytesIO

    buffer = BytesIO()
    buffer.write(template_content.encode("utf-8"))
    buffer.seek(0)

    return send_file(buffer, mimetype="text/csv", as_attachment=True, download_name="timetracker_import_template.csv")


@import_export_bp.route("/api/import/template/csv/clients")
@login_required
@module_enabled("import_export")
def download_csv_template_clients():
    """Download CSV import template for clients"""
    template_content = """name,description,contact_person,email,phone,address,default_hourly_rate,status,prepaid_hours_monthly,prepaid_reset_day,custom_field_erp_id,custom_field_debtor_number,contact_1_first_name,contact_1_last_name,contact_1_email,contact_1_phone,contact_1_title,contact_1_role,contact_1_is_primary,contact_2_first_name,contact_2_last_name,contact_2_email,contact_2_phone,contact_2_title,contact_2_role,contact_2_is_primary
Example Client,Client description,John Doe,john@example.com,+1234567890,123 Main St,100.00,active,40.00,1,ERP123,DEBT456,John,Doe,john.doe@example.com,+1234567890,Manager,primary,true,Jane,Smith,jane.smith@example.com,+1234567891,Assistant,contact,false
Another Client,Another description,,info@another.com,+0987654321,456 Oak Ave,150.00,active,,1,ERP789,DEBT789,Alice,Johnson,alice@another.com,+0987654322,Director,primary,true,,,,
"""

    from io import BytesIO

    buffer = BytesIO()
    buffer.write(template_content.encode("utf-8"))
    buffer.seek(0)

    return send_file(
        buffer, mimetype="text/csv", as_attachment=True, download_name="timetracker_clients_import_template.csv"
    )
