from flask import Flask, render_template, request, redirect, url_for, session, flash, send_file, jsonify
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime, timedelta
import os
from functools import wraps
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.pdfgen import canvas
from io import BytesIO
import json

app = Flask(__name__)
app.config['SECRET_KEY'] = 'a5bc902da518ef04a2fa00a9b12022caa558f08f00dfdccc5f2766dffc169194'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://lala8894_facturation:Lagier2025*@localhost/lala8894_facturation'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


# ============= Models =============
class Admin(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(255), nullable=False)
    email = db.Column(db.String(120), nullable=False)
    nom_entreprise = db.Column(db.String(200))
    adresse = db.Column(db.Text)
    telephone = db.Column(db.String(20))
    siret = db.Column(db.String(50))


class Client(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    nom = db.Column(db.String(200), nullable=False)
    email = db.Column(db.String(120), nullable=False)
    telephone = db.Column(db.String(20))
    adresse = db.Column(db.Text)
    siret = db.Column(db.String(50))
    date_creation = db.Column(db.DateTime, default=datetime.utcnow)
    devis = db.relationship('Devis', backref='client', lazy=True)
    factures = db.relationship('Facture', backref='client', lazy=True)


class Devis(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    numero = db.Column(db.String(50), unique=True, nullable=False)
    client_id = db.Column(db.Integer, db.ForeignKey('client.id'), nullable=False)
    date_creation = db.Column(db.DateTime, default=datetime.utcnow)
    date_validite = db.Column(db.DateTime)
    description = db.Column(db.Text)
    montant_ht = db.Column(db.Float, default=0)
    tva = db.Column(db.Float, default=20)
    montant_ttc = db.Column(db.Float, default=0)
    statut = db.Column(db.String(50), default='En attente')
    lignes = db.Column(db.Text)  # JSON


class Facture(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    numero = db.Column(db.String(50), unique=True, nullable=False)
    client_id = db.Column(db.Integer, db.ForeignKey('client.id'), nullable=False)
    date_creation = db.Column(db.DateTime, default=datetime.utcnow)
    date_echeance = db.Column(db.DateTime)
    description = db.Column(db.Text)
    montant_ht = db.Column(db.Float, default=0)
    tva = db.Column(db.Float, default=20)
    montant_ttc = db.Column(db.Float, default=0)
    statut = db.Column(db.String(50), default='Non payée')
    lignes = db.Column(db.Text)  # JSON
    relances = db.relationship('Relance', backref='facture', lazy=True)


class Relance(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    facture_id = db.Column(db.Integer, db.ForeignKey('facture.id'), nullable=False)
    date_envoi = db.Column(db.DateTime, default=datetime.utcnow)
    type_relance = db.Column(db.String(50))


# ============= Décorateurs =============
def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'admin_id' not in session:
            return redirect(url_for('login'))
        return f(*args, **kwargs)

    return decorated_function


# ============= Routes =============
@app.route('/')
def index():
    if 'admin_id' in session:
        return redirect(url_for('dashboard'))
    return redirect(url_for('login'))


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        admin = Admin.query.filter_by(username=username).first()

        if admin and check_password_hash(admin.password, password):
            session['admin_id'] = admin.id
            flash('Connexion réussie!', 'success')
            return redirect(url_for('dashboard'))
        flash('Identifiants incorrects', 'error')
    return render_template('login.html')


@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('login'))


@app.route('/dashboard')
@login_required
def dashboard():
    stats = {
        'clients': Client.query.count(),
        'devis': Devis.query.count(),
        'factures': Facture.query.count(),
        'factures_impayees': Facture.query.filter_by(statut='Non payée').count()
    }
    return render_template('dashboard.html', stats=stats)


@app.route('/clients')
@login_required
def clients():
    all_clients = Client.query.order_by(Client.date_creation.desc()).all()
    return render_template('clients.html', clients=all_clients)


@app.route('/client/add', methods=['POST'])
@login_required
def add_client():
    try:
        client = Client(
            nom=request.form.get('nom'),
            email=request.form.get('email'),
            telephone=request.form.get('telephone'),
            adresse=request.form.get('adresse'),
            siret=request.form.get('siret')
        )
        db.session.add(client)
        db.session.commit()
        flash('Client ajouté avec succès', 'success')
    except Exception as e:
        flash(f'Erreur: {str(e)}', 'error')
    return redirect(url_for('clients'))


@app.route('/client/edit/<int:id>', methods=['POST'])
@login_required
def edit_client(id):
    client = Client.query.get_or_404(id)
    client.nom = request.form.get('nom')
    client.email = request.form.get('email')
    client.telephone = request.form.get('telephone')
    client.adresse = request.form.get('adresse')
    client.siret = request.form.get('siret')
    db.session.commit()
    flash('Client modifié avec succès', 'success')
    return redirect(url_for('clients'))


@app.route('/devis')
@login_required
def devis():
    all_devis = Devis.query.order_by(Devis.date_creation.desc()).all()
    clients = Client.query.all()
    return render_template('devis.html', devis=all_devis, clients=clients)


@app.route('/devis/add', methods=['POST'])
@login_required
def add_devis():
    try:
        dernier_devis = Devis.query.order_by(Devis.id.desc()).first()
        numero = 1 if not dernier_devis else int(dernier_devis.numero) + 1

        lignes = request.form.get('lignes')
        tva = float(request.form.get('tva', 20))
        montant_ht = float(request.form.get('montant_ht', 0))
        montant_ttc = montant_ht * (1 + tva / 100)

        devis = Devis(
            numero=str(numero),
            client_id=request.form.get('client_id'),
            description=request.form.get('description'),
            montant_ht=montant_ht,
            tva=tva,
            montant_ttc=montant_ttc,
            lignes=lignes,
            date_validite=datetime.strptime(request.form.get('date_validite'), '%Y-%m-%d')
        )
        db.session.add(devis)
        db.session.commit()
        flash('Devis créé avec succès', 'success')
    except Exception as e:
        flash(f'Erreur: {str(e)}', 'error')
    return redirect(url_for('devis'))


@app.route('/factures')
@login_required
def factures():
    all_factures = Facture.query.order_by(Facture.date_creation.desc()).all()
    clients = Client.query.all()
    return render_template('factures.html', factures=all_factures, clients=clients)


@app.route('/facture/add', methods=['POST'])
@login_required
def add_facture():
    try:
        derniere_facture = Facture.query.order_by(Facture.id.desc()).first()
        numero = 1 if not derniere_facture else int(derniere_facture.numero) + 1

        lignes = request.form.get('lignes')
        tva = float(request.form.get('tva', 20))
        montant_ht = float(request.form.get('montant_ht', 0))
        montant_ttc = montant_ht * (1 + tva / 100)

        facture = Facture(
            numero=str(numero),
            client_id=request.form.get('client_id'),
            description=request.form.get('description'),
            montant_ht=montant_ht,
            tva=tva,
            montant_ttc=montant_ttc,
            lignes=lignes,
            date_echeance=datetime.strptime(request.form.get('date_echeance'), '%Y-%m-%d')
        )
        db.session.add(facture)
        db.session.commit()
        flash('Facture créée avec succès', 'success')
    except Exception as e:
        flash(f'Erreur: {str(e)}', 'error')
    return redirect(url_for('factures'))


@app.route('/generer_pdf/<type>/<int:id>')
@login_required
def generer_pdf(type, id):
    admin = Admin.query.get(session['admin_id'])

    if type == 'devis':
        doc = Devis.query.get_or_404(id)
    else:
        doc = Facture.query.get_or_404(id)

    client = doc.client

    buffer = BytesIO()
    pdf = SimpleDocTemplate(buffer, pagesize=A4)
    elements = []
    styles = getSampleStyleSheet()

    # En-tête
    title = f"{'DEVIS' if type == 'devis' else 'FACTURE'} N° {doc.numero}"
    elements.append(Paragraph(title, styles['Title']))
    elements.append(Spacer(1, 0.5 * cm))

    # Informations
    info_data = [
        ['Entreprise:', admin.nom_entreprise or 'N/A'],
        ['Adresse:', admin.adresse or 'N/A'],
        ['Client:', client.nom],
        ['Date:', doc.date_creation.strftime('%d/%m/%Y')],
        ['Montant HT:', f"{doc.montant_ht:.2f} €"],
        ['TVA:', f"{doc.tva}%"],
        ['Montant TTC:', f"{doc.montant_ttc:.2f} €"]
    ]

    info_table = Table(info_data, colWidths=[5 * cm, 10 * cm])
    info_table.setStyle(TableStyle([
        ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
        ('FONTSIZE', (0, 0), (-1, -1), 10),
        ('TEXTCOLOR', (0, 0), (0, -1), colors.grey),
        ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
    ]))

    elements.append(info_table)
    pdf.build(elements)

    buffer.seek(0)
    return send_file(buffer, as_attachment=True, download_name=f'{type}_{doc.numero}.pdf', mimetype='application/pdf')


@app.route('/envoyer_email/<type>/<int:id>', methods=['POST'])
@login_required
def envoyer_email(type, id):
    try:
        admin = Admin.query.get(session['admin_id'])

        if type == 'devis':
            doc = Devis.query.get_or_404(id)
        else:
            doc = Facture.query.get_or_404(id)

        client = doc.client

        # Configuration email (à adapter)
        smtp_server = "smtp.gmail.com"
        smtp_port = 587
        email_sender = admin.email
        email_password = "votre_mot_de_passe_app"

        msg = MIMEMultipart()
        msg['From'] = email_sender
        msg['To'] = client.email
        msg['Subject'] = f"{'Devis' if type == 'devis' else 'Facture'} N° {doc.numero}"

        body = f"""
        Bonjour {client.nom},

        Veuillez trouver ci-joint {'le devis' if type == 'devis' else 'la facture'} N° {doc.numero}.

        Cordialement,
        {admin.nom_entreprise}
        """

        msg.attach(MIMEText(body, 'plain'))

        # Attacher le PDF
        # (génération PDF simplifiée ici)

        server = smtplib.SMTP(smtp_server, smtp_port)
        server.starttls()
        server.login(email_sender, email_password)
        server.send_message(msg)
        server.quit()

        flash('Email envoyé avec succès', 'success')
    except Exception as e:
        flash(f'Erreur envoi email: {str(e)}', 'error')

    return redirect(request.referrer)


@app.route('/relance/<int:facture_id>', methods=['POST'])
@login_required
def envoyer_relance(facture_id):
    try:
        facture = Facture.query.get_or_404(facture_id)
        relance = Relance(
            facture_id=facture_id,
            type_relance=request.form.get('type', 'Automatique')
        )
        db.session.add(relance)
        db.session.commit()

        # Envoyer l'email de relance
        # (logique similaire à envoyer_email)

        flash('Relance envoyée', 'success')
    except Exception as e:
        flash(f'Erreur: {str(e)}', 'error')

    return redirect(url_for('factures'))

@app.route('/change-password', methods=['POST'])
@login_required
def change_password():
    admin = Admin.query.get(session['admin_id'])
    new_password = request.form.get('new_password')
    admin.password = generate_password_hash(new_password)
    db.session.commit()
    flash('Mot de passe changé', 'success')
    return redirect(url_for('dashboard'))

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
        # Créer un admin par défaut si aucun n'existe
        if not Admin.query.first():
            admin = Admin(
                username='admin',
                password=generate_password_hash('admin123'),
                email='admin@forvloc.fr',
                nom_entreprise='ForvLoc'
            )
            db.session.add(admin)
            db.session.commit()
    app.run(debug=True)