from uuid import uuid4
import os
import string
from sqlalchemy.orm import joinedload

from flask import (
    Blueprint,
    render_template,
    redirect,
    url_for,
    request,
    flash,
    current_app,
)
from flask_login import login_required, current_user

from app import db
from .models import Plant, PlantScientificName, PlantCommonName
from .forms import PlantForm
from plugins.media.models import Media
from plugins.media.routes import (
    save_media_file,
    delete_media_file,
    rotate_media_file,
    generate_image_url,
)


bp = Blueprint(
    'plant',
    __name__,
    url_prefix='/plants',
    template_folder='templates',
)

@bp.app_context_processor
def inject_image_helper():
    return dict(generate_image_url=generate_image_url)

@bp.route('/', methods=['GET'])
@login_required
def index():
    # ── 1) Read query-params ───────────────────────────────────────────
    page       = request.args.get('page',       1,   type=int)
    per_page   = request.args.get(
                    'per_page',
                    current_app.config.get('PLANTS_PER_PAGE', 12),
                    type=int
                 )
    view_mode  = request.args.get('view',     'grid', type=str)   # 'grid' or 'list'
    q          = request.args.get('q',        '',     type=str).strip()
    type_filter= request.args.get('type',     '',     type=str).strip().lower()

    # ── 2) Build base SQLAlchemy query ────────────────────────────────
    qry = (
        Plant.query
             .options(joinedload(Plant.media_items))
             .filter_by(owner_id=current_user.id)
    )

    # ── 3) Optional name search ───────────────────────────────────────
    if q:
        qry = qry.join(PlantCommonName).filter(
            PlantCommonName.name.ilike(f'%{q}%')
        )

    # ── 4) Optional type filter ───────────────────────────────────────
    if type_filter:
        qry = qry.filter(Plant.plant_type.ilike(type_filter))

    # ── 5) Apply ordering + paginate ─────────────────────────────────
    pagination = (
        qry.order_by(Plant.id.desc())
           .paginate(page=page, per_page=per_page, error_out=False)
    )
    plants = pagination.items

    # ── 6) Gather stats and distinct types as before ─────────────────
    stats = {
        'user_plants':  Plant.query.filter_by(owner_id=current_user.id).count(),
        'user_images':  Media.query.filter_by(uploader_id=current_user.id).count(),
        'total_plants': Plant.query.count(),
        'total_images': Media.query.count(),
    }

    plant_types = [
        row[0]
        for row in (
            db.session
              .query(Plant.plant_type)
              .filter_by(owner_id=current_user.id)
              .distinct()
              .all()
        )
    ]

    # ── 7) Render, passing both pagination AND per-page items ─────────
    return render_template(
        'plant/index.html',
        plants       = plants,
        pagination   = pagination,
        view_mode    = view_mode,
        q            = q,
        type_filter  = type_filter,
        per_page     = per_page,
        plant_types  = plant_types,
        stats        = stats
    )

@bp.route('/create', methods=['GET', 'POST'])
@login_required
def create():
    form = PlantForm()
    form.plant_type.choices = [
        ('plant', 'Plant'),
        ('cutting', 'Cutting'),
        ('seed', 'Seed'),
        ('tissue_culture', 'Tissue Culture'),
        ('division', 'Division'),
    ]
    form.common_name.choices = [
        (c.id, c.name)
        for c in PlantCommonName.query.order_by(PlantCommonName.name).all()
    ]
    form.scientific_name.choices = [
        (s.id, s.name)
        for s in PlantScientificName.query.order_by(PlantScientificName.name).all()
    ]

    if form.validate_on_submit():
        new_plant = Plant(
            uuid=str(uuid4()),
            owner_id=current_user.id,
            plant_type=form.plant_type.data,
            common_id=form.common_name.data,
            scientific_id=form.scientific_name.data,
            mother_uuid=(form.mother_uuid.data if form.mother_uuid.data != 'N/A' else None),
            custom_slug=(form.custom_slug.data.strip() or None),
            vendor_name=(form.vendor_name.data.strip() or None),
            price=(form.price.data or None),
            notes=form.notes.data,
            data_verified=form.data_verified.data,
            is_active=form.is_active.data,
        )
        db.session.add(new_plant)
        db.session.commit()
        flash('New plant created successfully.', 'success')
        return redirect(url_for('plant.edit', uuid_val=new_plant.uuid))

    return render_template('plant/create.html', form=form)


@bp.route('/<uuid:uuid_val>', methods=['GET'])
@login_required
def detail(uuid_val):
    # 1) load this plant (and its media) or 404
    plant = (
        Plant.query
             .options(joinedload(Plant.media_items))
             .filter_by(uuid=str(uuid_val), owner_id=current_user.id)
             .first_or_404()
    )

    # 2) load any child plants (same owner, mother_uuid pointing here)
    children = (
        Plant.query
             .options(joinedload(Plant.media_items))
             .filter_by(owner_id=current_user.id, mother_uuid=plant.uuid)
             .order_by(Plant.id)
             .all()
    )

    # 3) build linear nav of this user's plants (by insertion order)
    all_plants = (
        Plant.query
             .filter_by(owner_id=current_user.id)
             .order_by(Plant.id)
             .all()
    )
    uuids = [p.uuid for p in all_plants]
    try:
        idx = uuids.index(str(uuid_val))
    except ValueError:
        idx = None

    prev_uuid = uuids[idx - 1] if idx not in (None, 0) else None
    next_uuid = uuids[idx + 1] if idx is not None and idx < len(uuids) - 1 else None

    return render_template(
        'plant/detail.html',
        plant=plant,
        children=children,
        prev_uuid=prev_uuid,
        next_uuid=next_uuid
    )


@bp.route('/<uuid:uuid_val>/generate_children', methods=['POST'])
@login_required
def generate_children(uuid_val):
    parent = (
        Plant.query
             .filter_by(uuid=str(uuid_val), owner_id=current_user.id)
             .first_or_404()
    )
    try:
        count = int(request.form.get('count', 1))
    except ValueError:
        count = 1

    created = 0
    for _ in range(count):
        child = Plant(
            uuid=str(uuid4()),
            owner_id=current_user.id,
            plant_type='cutting',
            common_id=parent.common_id,
            scientific_id=parent.scientific_id,
            mother_uuid=parent.uuid,
            custom_slug=None,
            vendor_name=None,
            price=None,
            notes=None,
            data_verified=False,
            is_active=True
        )
        db.session.add(child)
        created += 1
    db.session.commit()

    flash(f"Generated {created} cuttings for {parent.common_name.name}.", 'success')
    return redirect(url_for('plant.detail', uuid_val=parent.uuid))

@bp.route('/<uuid:uuid_val>/edit', methods=['GET', 'POST'])
@login_required
def edit(uuid_val):
    plant = Plant.query.filter_by(
        uuid=str(uuid_val),
        owner_id=current_user.id
    ).first_or_404()

    form = PlantForm()
    form.plant_type.choices = [
        ('plant', 'Plant'),
        ('cutting', 'Cutting'),
        ('seed', 'Seed'),
        ('tissue_culture', 'Tissue Culture'),
        ('division', 'Division'),
    ]
    form.common_name.choices = [
        (c.id, c.name)
        for c in PlantCommonName.query.order_by(PlantCommonName.name).all()
    ]
    form.scientific_name.choices = [
        (s.id, s.name)
        for s in PlantScientificName.query.order_by(PlantScientificName.name).all()
    ]
    form.mother_uuid.choices = [('N/A', 'None')] + [
        (p.uuid, f"{p.common_name.name if p.common_name else 'Unnamed'} – {p.uuid}")
        for p in Plant.query.filter(Plant.uuid != plant.uuid).all()
    ]

    if request.method == 'GET':
        form.plant_type.data      = plant.plant_type
        form.common_name.data     = plant.common_id
        form.scientific_name.data = plant.scientific_id
        form.mother_uuid.data     = plant.mother_uuid or 'N/A'
        form.custom_slug.data     = plant.custom_slug or ''
        form.vendor_name.data     = plant.vendor_name or ''
        form.price.data           = plant.price or None
        form.notes.data           = plant.notes
        form.data_verified.data   = plant.data_verified
        form.is_active.data       = getattr(plant, 'is_active', True)

    if form.validate_on_submit():
        plant.plant_type    = form.plant_type.data
        plant.common_id     = form.common_name.data
        plant.scientific_id = form.scientific_name.data
        plant.mother_uuid   = (form.mother_uuid.data if form.mother_uuid.data != 'N/A' else None)
        plant.custom_slug   = (form.custom_slug.data.strip() or None)
        plant.vendor_name   = (form.vendor_name.data.strip() or None)
        plant.price         = form.price.data or None
        plant.notes         = form.notes.data
        plant.data_verified = form.data_verified.data
        plant.is_active     = form.is_active.data

        # (No more inline "featured_media_id" patch here—handled in media plugin)

        db.session.commit()
        flash('Plant updated successfully.', 'success')
        return redirect(url_for('plant.detail', uuid_val=plant.uuid))

    return render_template('plant/edit.html', form=form, plant=plant)


@bp.route('/<uuid:uuid_val>/upload', methods=['POST'])
@login_required
def upload_image(uuid_val):
    plant = Plant.query.filter_by(
        uuid=str(uuid_val),
        owner_id=current_user.id
    ).first_or_404()

    file = request.files.get('image')
    if not file or file.filename == '':
        flash('No file selected.', 'danger')
        return redirect(url_for('plant.edit', uuid_val=plant.uuid))

    try:
        media = save_media_file(file, 'plants', plant.id)
        media.uploader_id = current_user.id
        db.session.add(media)
        db.session.commit()
        flash('Image uploaded.', 'success')
    except Exception as e:
        current_app.logger.error(f"Upload failed: {e}")
        flash('Failed to upload image.', 'danger')

    return redirect(url_for('plant.edit', uuid_val=plant.uuid))


@bp.route('/<uuid:uuid_val>/delete/<int:media_id>', methods=['POST'])
@login_required
def delete_image(uuid_val, media_id):
    plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404()
    media = Media.query.get_or_404(media_id)
    delete_media_file(media)
    flash('Image deleted.', 'success')
    return redirect(url_for('plant.edit', uuid_val=plant.uuid))


@bp.route('/<uuid:uuid_val>/rotate/<int:media_id>', methods=['POST'])
@login_required
def rotate_image(uuid_val, media_id):
    plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404()
    media = Media.query.get_or_404(media_id)
    rotate_media_file(media)
    flash('Image rotated.', 'success')
    return redirect(url_for('plant.edit', uuid_val=plant.uuid))


@bp.route('/f/<string:short_id>')
@bp.route('/<string:short_id>')
def view_card(short_id):
    p = Plant.query.filter_by(short_id=short_id).first_or_404()

    # 2) owner → straight to the normal detail page
    if current_user.is_authenticated and p.owner_id == current_user.id:
        return redirect(url_for('plant.detail', uuid_val=p.uuid))

    # 3) everyone else → public card
    featured = next((m for m in p.media_items if getattr(m, 'featured', False)), None)
    return render_template('plant/card.html', plant=p, featured=featured)
